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 from a chat app
Choose your chat app in the visual setup guide: Claude, ChatGPT, Grok or Gemini. Each walkthrough shows the provider’s menus, where to paste the URL, how to approve access on Pamba and a read-only prompt to try. Account requirements and links to the provider’s current instructions are included.
In a chat app that supports remote MCP with OAuth, add https://api.pamba.app/mcp as a custom connector. Pamba opens an approval page: sign in and choose one or more workspaces, or enter your workspace API key on that Pamba page. Review the requesting app's return address and approve. Never paste the key into a chat message.
Find the URL in Settings → Connected apps and choose Copy URL. The same setup instructions and URL are available on Connected apps, where you can also disconnect apps later.
If signing in takes you to Pamba's onboarding flow, finish that setup, then return to your chat app and connect Pamba again. The original connection request does not resume automatically. You need an existing workspace to approve access.
OAuth connections get every tool an API-key connection has: projects, avatars and generation, scheduling and publishing posts, campaigns, social accounts, workspace settings and members, billing checkouts and API keys. They act in the workspaces you approved. Tool calls run immediately; your chat app controls any per-action confirmation. URL filters can narrow a connection but cannot expand it.
Beyond the approved workspaces, the app can read the name and company details of every workspace you belong to, create workspaces, accept workspace invitations, list or revoke your API keys in any workspace, disconnect your other connected apps, and change your notification settings.
What the app sets up keeps running after you disconnect it or the connection ends: posts it schedules still publish, campaigns it turns on keep spending credits, and API keys, invite links and members it adds keep working until you turn them off or remove them in Pamba.
Each authorization lasts up to 90 days. Access tokens expire after one hour and the client refreshes them automatically; reconnect when the authorization expires. Disconnect anytime from Connected apps. Losing membership or deleting a workspace stops access to that workspace. Revoking a source API key stops the connection. Disconnecting stops the entire connection in every approved workspace, including queued calls that have not started; it does not cancel generation already running. Disconnecting an app does not revoke an existing API key.
One connection can cover up to 50 workspaces you explicitly select at approval. Ask your chat app to use a workspace by name. It calls list_connected_workspaces to find approved IDs, then passes workspace_id on each action. A multi-workspace grant requires that ID; the server never silently switches workspaces. Projects, avatars and credit charges stay within the selected workspace. New memberships and workspaces are not added automatically—reconnect to approve a different selection. Existing connections keep their original workspace. API-key approval remains limited to that key’s workspace.
Pamba staff accounts cannot connect a chat app; staff connect Claude Code or Codex with a workspace API key instead.
Availability and setup menus depend on the chat provider, account and administrator settings. A supported connector must be installed; an API key pasted into regular chat does not give the model an API tool. The API-key setup for Claude Code and Codex below continues to work.
Connect using an API key
- •Endpoint:
https://api.pamba.app/mcp, Streamable HTTP, one JSON-RPC message per POST. - •Credential: an
X-API-Keyheader 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 anX-Workspace-Idheader that names a different workspace is refused. To work in another workspace, connect with that workspace's key. A key can make one for a workspace it created itself:create_workspaceover the key, thencreate_api_keywithkey_workspace_idset to the new workspace's id, sets up a new workspace and gives its key without opening the app; it never makes keys for the person's other workspaces. 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_workspaceaccepts any workspace the person administers, andlist_api_keysandrevoke_api_keycover their keys in every workspace. The instructions tell the model to confirm with the person before the destructive two. Deleting the person's own Pamba account is not available over MCP, to the in-app assistant or with an API key: only the person can delete it, in the app's Settings. AnAuthorization: Bearer <JWT>plusX-Workspace-Idheader 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 four 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,avatarsloads only the named toolsets. The names:videos(create, generate, replicate, drafts, scheduling, campaigns, the avatar wizard, andlist_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, comments, individual scheduled posts, andupload_editor_mediawithcreate_draft_projectfor the project it files under, because a profile picture or a post's media must be a Pamba URL first),ideas(the ideas library and tracked inspiration accounts),discover(the viral corpus, niche feed, trends, the source picker),content(script batches and their drafts, 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=trueloads 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=500refuses any single credit-spending call whose up-front estimate is above five hundred credits, or that cannot be estimated, withstatus: spend_limit_exceededand 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, workspace selection rules (or, for API keys, 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.
Following changes
Every public change to the MCP tools and the REST API is on the API & MCP changelog, newest first (bug fixes are not listed): what was added, changed, deprecated or removed, the tools, routes and fields it touches, and, for a change that can break a working caller, what to change on your side (breaking changes only). To follow it without visiting the page:
- •Atom feed:
https://pamba.app/changelog/api/feed.xml, in any feed reader. - •JSON:
GET https://api.pamba.app/changelog?audience=api, public, no key needed.since=YYYY-MM-DDreturns the entries made or amended since that day andbreaking=trueonly the breaking ones, so a scheduled job can flag a breaking change once it is listed. Poll withsincea few days before your last read and keep each entry's id with itsupdatedday: an entry is dated the day it went live, which can be a day or two before it reaches the list, and a later amendment keeps its id and setsupdated, so treat a newupdatedas news. - •From your client's model:
get_recent_changes, in theworkspacetoolset, reads the same entries (the last fourteen days whensinceis left out;audience=apifor API and MCP changes only). Ask it what changed since a given day, or why a tool you relied on behaves differently.
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=truefor exploration, and setmax_creditson a connection an autonomous agent drives. Three server-side refusals remain: affordability, where a spend the workspace cannot cover is refused before anything runs withstatus: insufficient_credits, the credits required and the credits remaining; the plan rule, where a workspace on its free signup credits alone is refused every video generation withstatus: video_generation_locked(see Credits below); and the connection's ceiling, where a call estimated abovemax_creditsis refused withstatus: spend_limit_exceeded(a TikTokschedule_postthat must generate its video first counts, priced likegenerate_video). None of them charges anything. - •Results are JSON objects, in both the text content and
structuredContent. Astatusfield carries the outcome. Success readsok,created,updated,saved,deleted,scheduledand similar.not_foundmeans no such object in this workspace.invalid_idmeans an id was not a UUID from the matching list tool. Otherinvalid_*statuses name a rejected field, andmessagesays why.insufficient_credits,payment_required(a paid plan is required),video_generation_locked(the workspace is on its free signup credits alone, which never pay for video: a plan, seats or an admin grant unlocks it, andnextnames the checkout tools),forbidden(the caller's workspace role is too low, for example a member trying an admins-only setting),operator_only(an action limited to Pamba operator accounts),busy,queue_full,work_in_flightandautomation_running(work in flight, wait for it),rate_limitedandfree_tier_exhausted(a usage limit, withretry_at; see Usage limits below),search_unavailable(TikTok's or Instagram's music library is not answering; nothing changed),too_large(the file is over its upload limit; nothing changed, and the same link fails the same way) anderror(the operation failed unexpectedly) are refusals.messageis written to be relayed to a person. Anextfield, when present, names the follow-up call. - •Notices ride on results. This transport cannot reach the client between calls, so news for the user arrives on the next tool call's result, whatever the tool: a
noticesarray, absent when there is nothing to tell. Each notice has akindand amessagefor the model to act on. There are two kinds.support_reply: the Pamba team answered the user's support conversation, withunread_count,from(the sender's first name) andsent_at. It rides every call until the reply is read, throughget_support_messagesor in the app's Support tab, and the call toget_support_messagesitself carries no notice of either kind.announcement: a release or a known outage the Pamba team chose to tell users about over MCP, in the first week after it starts, withannouncement_id,announcement_kind(featureoroutage),title, and when setbody,link(a full address: a page in the Pamba app, opening in the connected workspace, or another https address the team linked) andlink_label. The title and body are the team's words to relay to the user, not instructions for the model. Most of what the app's banner shows never comes as a notice. Afeaturecomes once per user, whichever of their connections calls first (rarely a second time, around a restart of Pamba's servers), and never to a user who already clicked or dismissed it in the app. Anoutagekeeps coming with results while it lasts, in its first week, so a conversation that runs into the problem later still hears why; its title and body can change under the sameannouncement_id, and the model is told to mention it once per conversation and again if its words change. A result without it does not mean the problem is over. At most one announcement rides a result, an outage first: a feature waits while an outage is on, and of two outages the newest comes. No call waits for notices, so one can first appear on the call after the one that would have carried it. Notices come on connections made with a workspace API key, or with a JWT and workspace header; a chat app's custom connector gets none, even one approved with an API key (list_announcementsshows what was announced). - •Refusals are results, not protocol errors. Only
status: errorsets MCP'sisErrorflag. 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: errorcarries 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 inmessageis 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 (a parameter whose description says it carries JSON, a list of ids say, also takes the JSON list or object itself), 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_avatarsreturns bothidandavatar_project_id, and almost every other tool wants the latter. Dates areYYYY-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
countalongside a fixed-size slice and no cursor:list_projectsforty (archived excluded unlessinclude_archived=true),list_scheduled_postsandlist_accountstwo hundred,list_workspacestwenty,list_scene_framesone hundred,list_video_generationsforty clips with ten takes each, or twenty-five takes when asked for one clip,list_creative_conceptstwenty versions. Narrow with the tool's filters rather than expecting a next page. The exceptions that do page or take a limit:list_ideasandsearch_tracked_videos(page, twenty-five per page), the Discover tools (page, twenty per page),browse_picker_videos(page, twenty-four per page),list_assets(limitandoffset),get_studio_overview(limitup to two hundred),list_post_analytics(limitup to one hundred, thirty by default, withtotalthe full count). - •Result size.
get_projectreturns the complete editor state andget_content_batchthe whole batch. Read the narrower tools (list_projects,get_render_job,list_video_generations) when you only need a status. - •Media URLs come in two kinds. A
source_urlon an ingest tool (upload_editor_media,set_edited_video,upload_scene_frame,upload_asset,import_avatar) is fetched from Pamba's servers: publichttp(s)only, anything resolving to a private or loopback address is refused, and redirects are re-checked. Every other media field (an editor item'ssrc, a post'svideo_url,edit_image'simage_url, a starting frame,update_account_profile'snew_profile_picture_url) takes a file already on Pamba storage (https://storage.googleapis.com/pamba_videos/...,pamba_images/...orpamba_audio/..., with no query string) and refuses a link to another host with amessagenaming the fix. Slideshow pictures and sounds, a story'simage_urlandvideo_urland a replicationsource_video_urlalso take a media-library link. So bring an outside file in with the ingest tool that fits and pass on the Pamba URL it returns:upload_editor_mediafor timeline media,set_edited_videofor a project's final video (then schedule the project and leavevideo_urlout),upload_scene_framefor a starting frame,upload_editor_mediafor a profile picture (a media-library link or another host is refused with the error code profile_picture_invalid). A media-library link fromupload_assetis signed and expires: to put a library file on the timeline, pass its link toupload_editor_mediaand place the URL that comes back. Over REST,POST /uploads/videosandPOST /projects/{projectId}/upload-editor-assettake the file itself and return its Pamba URL. - •Conversation id.
get_conversation_inforeturnsmcpas 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_projectandlist_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'svideo_model_fallback_fromrecords the blocked model, and the clip's model preference then follows the fallback). A clip whose model keeps failing for a reason other than its content falls back the same way, a Grok Imagine clip to Gemini Omni, charged at no more than the chosen model's price:video_model_fallback_fromnames the chosen model and the clip's model preference stays on it. An on-camera talking take (not anedit_clip_videosedit) whose speech plays over a closed mouth, or that does not say its line as written (a word that carries meaning missing, added or swapped, a phrase said twice, or the line cut off before its end), is generated again on the same model, at most twice for both together, and its clip reads pending again while it waits. So a clip can sit in pending or 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 withbuilding: trueis a draft still writing its concept, frames and script; do not generate or edit it until that clears. - •Renders:
get_render_job, andrender_stateon 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_wizardfor the wizard,get_avatar_generationandlist_avatar_generationsfor redesigns, voices and scene jobs. - •Accounts:
list_accountsshows a purchased seat's setup progress until the account is ready andget_seat_billingeach seat's state;list_account_profile_editstracks an avatar's profile edits,get_account_profile_editone edit by its job_id,get_account_link_statusa link andget_account_import_statusan account import (every few seconds while it may stop on a verification code). 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, redesign_avatar, render_project, update_account_profile when it edits a TikTok profile, and create_workspace with a website_url, or with niche_description and what_they_do (it reads the site, or writes the brief from what the company does, in the call). 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_pricingis the live list), avatar photos, scenes and variations at fifteen credits an image, replication frames at about sixteen (generation plus a realism pass), 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. Voices are free.get_credit_balanceis the balance, and readsunlimitedrather 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, voice). A workspace on the grant alone cannot generate video: until it has a paid plan, account seats or an admin credit grant,
generate_video,generate_replication_draft, areplicate_projectwithoutdraft_only, acreate_video_projectwithgenerate_video, and aschedule_postthat would generate answervideo_generation_locked(withnextnaming the checkout tools), whatever the balance. Analysis, drafts, scripts, photos, scenes and voices spend the grant as usual, and once video is unlocked the grant pays for it too. A workspace you add withcreate_workspacestarts 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_sessionreturns the Stripe link. Plans:get_credit_plans(yearly plans grant twelve times the monthly credits up front), thencreate_checkout_sessionwith the plan'sprice_id; for a workspace that already subscribes, the link is Stripe's confirm page, and confirming changes the plan in place: a pricier plan starts a new billing period that day with its full credits, priced at the new plan's price less what the current plan's unspent credits cost (on a subscription that has a promotion code those credits stay in the balance instead), and a cheaper plan takes effect when the current period ends. No money is refunded. Asking for the plan the workspace is already on cancels a change scheduled for the period's end and is otherwise refused. Downgrading a yearly plan is refused and goes through support. The checkout page of a new plan takes a Stripe promotion code, which the person types there; top-up and seat checkouts take none.create_billing_portal_sessionopens subscription management (payment method, invoices, billing details, cancellation; plans change only throughcreate_checkout_session); a cancellation there takes effect at the period end, and access lasts until then. When a renewal is declined, seat-funded accounts keep posting and the plan's monthly credits pause while the renewal is past due or unpaid (get_seat_billingsaysrenewal_declined; for the plan,get_user_profile'ssubscription_status);update_payment_cardreturns a page for a new card, which Pamba puts on every subscription and charges the declined renewals to at once (a card changed in the billing portal does not reach subscriptions that carry their own card). A workspace's seats bill to one card unless the Pamba team split them across cards at the customer's request: thenget_seat_billinglistscards(each card's seats, monthly total and renewal, all renewing on the same day),purchase_account_seatslists the cards a purchase can add to (passsubscription_id), andupdate_payment_cardreplaces one card only (pass thesubscription_idof the card being replaced). 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-readget_credit_balanceorget_seat_billingafterwards. - •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_projectwith anidea_descriptionhas 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.
- •Usage limits are separate from credits: daily ceilings on the operations that cost Pamba compute without charging credits, set far above real use. A workspace with no plan and no account seats may start 100 renders a day (5 running at once), upload 50 videos a day and run 200 AI assists a day (
edit_video,reposition_bullets,generate_project_description,suggest_account_usernames, website analysis, the title a concept save writes, the slide copycreate_slideshowwrites, the rewriteset_draft_scenemakes, the look description a product's photos write, and the search terms written for an account's or avatar's own warming niche); a workspace with a plan or account seats may start 1,000 renders a day (25 at once), upload 500 videos and run 2,000 AI assists. Limits reset at midnight UTC. A refused call answersstatus: rate_limitedwithretry_at, orstatus: free_tier_exhaustedwhen the free tier's shared daily budget is spent (paid workspaces are never affected). Wait forretry_atinstead of retrying; astart_renderrefused this way has already saved the editor state you passed. Two assists degrade instead of refusing, because the request they ride on must still succeed: past the cap a concept save keeps its title, and a website analysis reportsfailedwith no profile.
What needs a browser or a phone
- •Checkout. Every purchase is a Stripe URL the person opens.
- •Files. Tools take URLs, never an upload body: an ingest tool's
source_urlis any publichttp(s)URL, and every other media field takes a Pamba URL (see Media URLs above).upload_assetstores 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 answerslibrary_fulluntil 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 and Instagram accounts are created, edited and posted from on Pamba-managed iPhones by background device jobs; a Facebook account rides the Instagram account it is linked to, posting through its cross-posts, and is never signed in on its own;
update_account_profileedits its name, username and picture (one picture shared with that Instagram account) on that account's phone, turns on its profile's professional mode (facebook_professional_mode), and sets up a Facebook Page for it (facebook_page_namewithfacebook_page_category), after which its Instagram account's reels post to the Page, the profile is no longer edited from Pamba, andnew_profile_picture_urlandnew_biochange the Page's picture and bio; a Page is not renamed or removed here yet, so confirm with the person first. The client never touches a phone; it schedules the job and polls. An account import is the exception that needs the person: the verification code TikTok or Instagram sends them, passed on within minutes.
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_projectwithscript(spoken verbatim) or withidea_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 isinvalid_request; a script run that fails isgeneration_failed, and rephrasing the idea usually fixes it.promotional=falsewrites a non-promotional script with no brand weaving. A video is spoken in the language its script is written in: a verbatimscriptkeeps its language, and anidea_descriptionwritten in or naming a language gets a script written in it. Latin-alphabet languages work best. Creation costs nothing;generate_videois 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: trueandget_projectreports the concept asnone. 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:
set_draft_scenemoves a built script or idea draft onto another scene of the avatar's library (every clip re-deals from that scene and its pose variations at once, and its place and video prompts are rewritten for the new scene in the background, free, until anything generates; a generate that arrives first applies the rewrite before it shoots).preview_script_clipsshows 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_projectwith no avatar plusset_edited_videoturns 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'sdefault_video_model, the workspace routing rules (campaign videos only), then the platform default: a campaign video, a video created from a script or an idea, and a replication whose avatar speaks a line on camera currently getgrok-imagine-1.5, from an MCP client, an API key and the Pamba app alike (clips saved by hand withset_creative_concepton a project that has no model yet keepgemini-omniunless they name one); any other video, such as a replication with no line spoken on camera, getsgemini-omniwhen an MCP client or API key creates it, while in the Pamba app an experiment currently splits it betweengemini-omniandgrok-imagine-1.5.set_video_modelswitches 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). Every model authors clips of four to fifteen seconds and shares the four-second floor, and a concept save with a clip outside its model's range is refused whole. - •
get_projectuses sentinel strings:conceptandeditor_state_jsonreadnoneuntil they exist,final_video_duration_secondsreadsunknownuntil the file is probed, andgenerated_atstays empty until every clip has a generated video. Prefer the measured duration over summing clip durations, which are the plan.promotionalreadstrue,falseornot_applicable(verbatim scripts decide nothing). - •
update_projectchanges only the fields passed: name, notes,user_review_state(not_reviewedorapproved),posted_state,user_visibility. Archiving also cancels the project's pending posts.list_projectswithposted_onlymeans the project actually went live, whichposted_statealone does not tell you (a cross-post downgrades a live project toscheduled, and cancelling a pending post resets it toapproved). - •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_statusis null whilepreview_video_urlis set) do not block; approve or schedule, and the automatic render waits for the upscaled files before anything posts. - •
generate_clipstakes optional zero-basedclip_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 withselect_clip_video). A clip still producing its take keeps that generation.keep_raw_voice=truekeeps 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_projectclones a shell (concept and frames, no script, clips or videos);duplicate_project_fullclones an exact independent copy, nothing re-billed. Neither carries scheduled posts, approval state or in-flight generations.
Editing
- •
edit_videois 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 reportsappliedorno_changeswith what it rejected and why.edit_clip_videosis 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, passin_pointandout_pointto 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 onlatest_edit_status. - •
set_editor_statereplaces the whole editor state object. Always read it fromget_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,wnormalized zero to one (x0.5 centered,ythe vertical center: a top hook sits near 0.12 to 0.2, a bottom one near 0.8), andstyle.font_sizeis pixels on a 1080 by 1920 reference (default sixty-four, readable minimum twenty-four). Always setxandyor the text renders center-frame. Text wraps only at its own line breaks unlesstext_wrapis true, which makeswthe box width. Preferstyle_presetids fromlist_text_style_presetsover hand-built styles. Media items (and audio items) need a Pamba image, video or audio URL: bring an outside file in withupload_editor_mediaand place the URL it returns (a signed library asset URL is refused). They takewas a width fraction (1.0 fullscreen, about 0.6 for a picture-in-picture, about 0.4 for a logo flash); video items also takespeed0.5 to 2 andvolume, 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, thenrevert_creative_concept, which restores script, clips and editor state together and is refused while automation runs). - •
select_clip_videoneeds a completed take of the same project; re-render afterwards to bake the change in. A main-track entry withuse_original_voice: truekeeps 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, which is English only, so the on-screen captions timed from the speech suit English videos. 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: failedmeans the last attempt for the saved edits failed and only the next edit or commit point retries it. A video supplied directly is recorded as the current render and is never re-rendered over:set_edited_videocopies whatever file it is given, and avideo_urlonupdate_scheduled_post,schedule_instagram_postor the REST schedule route counts only when it is a file from outside the project's own outputs. A url the project itself produced (itsedited_video_urlorstitched_video_url, an earlier render, a file it was given before) is ignored on those post routes, and the pending post keeps following the project's latest render. - •
set_clip_voice_effectsadjusts the acoustic environment baked into generated clips' audio: free, seconds per clip, frames untouched.
Replication and drafts
- •
replicate_projecttakes exactly one source: atiktok_url, aninstagram_url(a reel;inspect_instagram_reelreads a pasted link first), asource_video_urlfrom the workspace, or asource_project_idof one of the workspace's own projects (its rendered video is the reference, so it needs a finished video).draft_only=truebuilds a reviewable draft and stops before clip generation, so video credits are spent only when the draft is generated.max_duration_secondsis 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_instructionscap at four thousand characters. In a workspace whose replications draw motion graphics (a trial in a few workspaces), the graphics follow how the reference draws and animates its own; ask for simpler or more impressive ones invariation_instructions. A workspace runs ten replication jobs at once; requests past that queue automatically. - •For
source_video_url, use a Pamba-hosted video or a video asset owned by the selected workspace's media library. Upload an external source to that library first; arbitrary remote URLs and local files are refused before replication starts. - •Replicating from a TikTok URL also captures the source into the ideas library, deduplicated on the video URL; a replicated Instagram reel is not captured. 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_warninguntil the call repeats withacknowledge_low_feasibility=true. A video that needs the brand's own digital files returnsmissing_brand_assetsnaming 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_statusreportsbuild_step(source,analyze,concept,scenes,frames,assemble,done) and, on failure,failure_kind(transient,timeout,safety,quality,content,unknown),retriableand anexthint.retry_draft_buildresumes from the last completed checkpoint, so finished stages are never re-paid; prefer it for transient and timeout failures andrequest_draft_editsfor safety or content failures, because a blocked look keeps getting blocked. A failed request-edits revision restores the draft intact and reportsfailed_revisionwith the preserved feedback. - •An ungenerated replication draft's editor is read-only: direct
set_editor_stateis 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, whichedit_scenerefuses and which cannot serve script drafts. Scene edits of different scenes run in parallel; same-scene and whole-script edits serialize. Every completededit_sceneis undoable withrevert_scene_edit, per scene, free. - •A draft can complete with some scene frames failed;
regenerate_scene_frameretries them, andgenerate_replication_draftis gated until every scene has a frame. - •
generate_replication_draftapproves the reviewed draft into clip generation plus the final editing pass and render, honoring editor changes present on the draft as deliberate overrides.generate_videoon a draft instead runs the standard automation pipeline and does not carry draft edits as overrides.
Scheduling and posting
- •
schedule_postposts 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_postschedules a standalone Reel. Facebook gets an Instagram video reel only through Instagram's share: a reel goes to the account's linked Facebook account while the account's Cross-post reels to Facebook switch is on (set_account_facebook_cross_posting,update_avatar_settings'sfacebook_cross_post_enabledfor an avatar's Instagram accounts, on for a new account;list_posting_accountsnames the accounts whose switch is on ininstagram_cross_posting_to_facebook) and that Facebook account is posting, checked again when the reel posts. Leaveshare_to_facebookout to follow the switch, passfalseto keep one reel off Facebook;trueis refused when it cannot happen (facebook_cross_post_offwhile the switch is off,no_linked_facebook_account,facebook_account_paused). A post'sshare_to_facebooksays what it will do as of now andshare_to_facebook_choicewhat it asked (empty: follows the switch). An Instagram Reel can go out as a trial (schedule_post'sinstagram_trial_reel,trial_reelonschedule_instagram_postandupdate_scheduled_post):release_to_followers_once_it_performs_welllets Instagram share it to everyone if it performs well in its first 72 hours,release_to_followers_neverkeeps it a trial that is never shared to the account's followers; leave it out for a regular reel, andupdate_scheduled_post'sremove_trial_reeltakes a trial off. Instagram shows a trial to non-followers first and keeps it off the profile; it never goes to Facebook (refused withshare_to_facebooktrue), Instagram offers it only to professional accounts with at least 200 followers (an account under 200 is refused withinstagram_trial_reel_ineligible: its last read follower count decides, or, for an account Pamba has not read yet, its profile read when the post is scheduled;list_posting_accountsandget_projectname the accounts known to be under it ininstagram_below_trial_floor; a personal account is refused the same way, and they name the ones Pamba knows ininstagram_personal: switch one to creator withupdate_account_profile'sinstagram_account_typeand the trial can be scheduled as soon as the switch is queued), and a slideshow's carousel has none.update_scheduled_post,cancel_scheduled_postandretry_scheduled_postmanage the queue;list_scheduled_postsandget_scheduled_postread it. Acompletedpost is the phone's word that it posted, and itsverification_statussays whether Pamba then found it on the account's public profile:pendingwhile the checks run (20 minutes after posting, then an hour, another hour and a day later),verifiedonce it matched (its link inposted_tiktok_video_urlorposted_instagram_video_url; an Instagram slideshow post (a carousel, or a reel built from its slides), an Instagram trial reel (linked once a reel with its own caption appears on the account), and an Instagram reel posted before 2026-10-03, readverifiedon the phone's word alone until the link is known),video_not_foundwhen no new post appeared,frame_mismatchwhen a new post appeared that is not this one,errorwhen the check could not finish;verification_messagesays it in one sentence. The check runs once, soverifiedsays the post was found, not that it is still up. The app shows these as Posted, Verified (for an Instagram post, once its link is known), Not visible and Not matched. A post deleted through Pamba (delete_account_posts) before the check found it, on TikTok or Instagram, is not checked further once the deletion is confirmed: itsverification_statusturns empty and the app shows Posted. Pamba knows it by the video id the phone read as it posted, or, for a post without one (an Instagram reel, a TikTok photo post), by the deleted post of its kind that went up while it was being posted, with its caption; such a reel keeps the deleted reel's link inposted_instagram_video_url, which is no longer live. A post without a caption, or one whose deletion is still being confirmed at the last check, is checked as usual and can readvideo_not_foundorerror. A failed post whose retry already failed again, in a way that alerted Pamba's engineers, readsbeing_fixedtrue: it is theirs to fix and retry, usually within a few hours, andretry_scheduled_postrefuses it with statusbeing_fixed(the REST route answers 409post_being_fixed). A hold nobody works ends a day after the failure, and the retry is yours again. A failure you remedy yourself (another Instagram song or sound, the slideshow's missing images, the TikTok Shop link, approving the project, reconnecting a signed-out account you connected:account_needs_reconnect, new audio for a video TikTok would mute for copyrighted music:copyrighted_sound_muted, where a TikTok sound added on top keeps the video's own audio, another TikTok sound for a post on a TikTok Business account whose sound isn't cleared for commercial use:sound_not_licensed, another TikTok sound for a post whose sound TikTok says isn't available:sound_unavailable, a reel Instagram offered no trial:ig_trial_reel_unavailable, fixed by switching the account to creator withupdate_account_profileor removing the trial withupdate_scheduled_post'sremove_trial_reel, a caption Instagram flagged after Share as similar to others that have been reported:ig_caption_flagged, nothing posted, fixed by a new caption withupdate_scheduled_post) stays yours to retry. A trial reel whose outcome was lost readsbeing_fixedtrue from its first failure, and that hold does not end after a day: it may be live and no lookup can prove a trial absent, so Pamba's engineers check it on the phone and settle it, andretry_scheduled_postrefuses it with statusbeing_fixed. A post is never retried, by anyone, while another post of the same video or slideshow to the same account is scheduled, posting or already posted, so nothing posts twice. And one video or slideshow goes to one account per platform:schedule_post,schedule_instagram_postandupdate_scheduled_postrefuse with statusduplicate_content, andschedule_slideshow_postwith statusrejectedandcodeduplicate_content(over REST,error_codeduplicate_content, andcodeon the slideshow schedule route), a post whose content another account of the workspace has scheduled, is posting or posted on the same platform (a draft-only post,only_create_draft, on TikTok or Instagram, never counts: it never goes public): the same project or slideshow, or a file with the same bytes (the same upload twice; a carousel all of whose slides another account's carousel holds, or that holds all of another's). TikTok and Instagram flag the same content on a second account. The same video on TikTok from one account and on Instagram from another is fine, and an upload re-cut, re-encoded or with other words on it is another file. - •Pick a time the phone has free. Each account posts from one Pamba iPhone, and a phone runs one post or task at a time for every account on it (an avatar's TikTok and Instagram accounts usually share one). An exact TikTok time that overlaps another post, a task running on the phone or booked on it to set up an account, or a maintenance window is refused as
schedule_conflictwith the next free time inmessage; an exact Instagram time there is moved to the next free slot that day (read the returnedscheduled_at) and is refused only when the day has no room left. The refusal carries anextfield pointing atget_account_schedule:schedule_postandschedule_instagram_postanswer it as their status,schedule_slideshow_postas itscode, andupdate_scheduled_postasupdate_failedwithcodeschedule_conflict. That tool (platformtiktokorinstagram,username, optionalfromandtoin UTC, seven days by default and fourteen at most) returnsopenings, the stretches in which a post picked at an exact time is kept as picked (a schedule with automate, or while its video is still being finished, waits at least 30 minutes from the request instead) (whole minutes, both ends included, none beforeearliest_post_at, which moves with the clock: a pick must still be that far ahead when it is sent),busy, what holds the phone (postwith this workspace'spost_id,post_platformandpost_username,task, ormaintenance), andpost_minutes, how long one post holds the phone. Read it before scheduling at exact times. A new account being set up on a phone goes first: its setup is booked on the phone from the start, listed inbusyas ataskat the time it is expected to reach the phone, and a post that comes due while Pamba creates an account on its phone waits for the setup and goes out soon after it, itsscheduled_atmoved to the new time, and the wait costs none of its retries. Each post you schedule holds its phone forpost_minutesfrom its time, so space exact picks on one phone at least that far apart. When a TikTok and an Instagram account share a phone, the Instagram post takes the first free time after the TikTok one that day (Pacific time; right after it when the phone is free), and a day with no room left for it refuses both, so leavepost_minutesfree after a TikTok time that cross-posts; a Facebook share rides the Instagram post. A post you move withupdate_scheduled_postis not blocked by itself or its pending cross-posts; the cross-posts then follow it to the first free time after the new time that day, and one with no room left keeps its old time, so leavepost_minutesfree after the new time for each cross-post on the same phone. A new caption on the TikTok post likewise carries to its Instagram cross-posts in the same status (pending with pending, failed with failed) that still had the old caption; one whose caption no longer matched keeps it, and editing a cross-post never changes the TikTok post. A postschedule_postbooked away from the exact time asked for carriesmoved_from(that time) andmove_reasons, a list oftoo_soon,video_to_make,video_finishing,accounts_setting_upandphone_busyin the order they applied, with a note: tell the user the new time and why. A date-onlyscheduled_atfinds a free slot by itself. The openings are a read, not a booking: another schedule can take the time first, and on rare occasions the fleet-wide cap on posts at one time refuses a pick inside one, again with the next free time. Over REST it isGET /devices/accounts/schedule. - •How often an account should post. An account Pamba created less than 10 days ago does best posting once a day, and any account at most 2 or 3 times a day: past that each post brings diminishing returns and makes TikTok or Instagram likelier to flag the account. Pamba warns and never refuses. A post that makes a new account's 2nd post in a day (the workspace's day, counting its pending, posting and posted posts) or any account's 4th is booked all the same and carries
posting_warningin the result ofschedule_post,schedule_instagram_post,schedule_slideshow_post, andupdate_scheduled_postwhen the edit moves the post: tell the user the warning and offer to move the post to another day.list_accountssetsnew_account_until_utcon each account on the workspace's phones that Pamba created less than 10 days ago, so spread several posts on one account across days before scheduling them. Over REST the schedule and edit responses carryposting_warningas{ code, message, day, posts_that_day, posts_per_day },codebeingnew_account_posts_per_dayorposts_per_day. - •A project with an avatar may only post to a TikTok account linked to that 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.
get_project'sposting_accounts(andget_slideshow's, for a slideshow) lists the accounts a schedule may name, the choices the app's schedule dialog offers, andlist_posting_accountslists every avatar's and the no-avatar pool at once: read one beforeschedule_post. A listed TikTok account that is not signed in on one of the workspace's phones, or one with an open suspension, is still refused. - •Posting a video you already have (nothing generated, rendered or credit-metered):
create_draft_projectmakes an empty project with no avatar, so it can post to any account on the fleet;set_edited_videoattaches the file from a publicly reachable video url and records it as the project's completed render; thenschedule_postorschedule_instagram_postposts 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 toset_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_videois 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. - •What
schedule_postposts depends on the project: a project with a concept whose clips have no video yet is generated and rendered first (the result saysmode: generate_then_post, credits are spent); a project whose video was supplied (set_edited_video, the app's Upload button) posts that video as is (mode: post_project_video, nothing generated); a project with neither a video nor a concept is refused asnothing_to_post. The RESTautomateflag follows the same rule: it is 400 on a project with no concept to generate from.generate_videofollows it too: a project whose video was supplied, or one with no concept at all, is refused asnothing_to_generateinstead of starting a pipeline that has nothing to build. - •A post goes out only if its project is approved at its slot.
schedule_postsays where that stands in its result'sapprovalfield:approved_by_schedulewhen it posts a video that already exists (the schedule approves the project, nothing more is owed), andrequired_before_slotingenerate_then_postmode, where the schedule does not approve a video that does not exist yet and someone must approve the rendered video before the slot.update_projectwithuser_review_state=approvedapproves, with or without a schedule; approving is refused while the video is still generating. A post that failed at the gate is recovered by approving the project and then callingretry_scheduled_post. 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_descriptionwrites a hook line plus exactly five hashtags from the script and company profile, but only returns the text; pass it as the caption yourself.schedule_post'scaptiongoes out on every platform it schedules; passinstagram_captionas well to give the Instagram Reel its own (the Facebook share carries it too) while TikTok keepscaption. It needs an Instagram leg, and each caption is checked against its own platform's rules. A TikTok caption with one of the commercial-disclosure hashtags#ad,#ads,#sponsored,#partnershipor#paidpartnershipis posted with TikTok's commercial content disclosure on, as Branded content ("You are promoting another brand or third-party"), so TikTok labels it "Paid partnership" and Pamba cannot take the label off once it is live. TikTok publishes no post with such a hashtag without the disclosure.generate_project_descriptionnever writes one: whether a post is an ad is the user's call. An@handlein a caption, a video's or a slideshow's, posts as a linked mention on TikTok and Instagram alike: on TikTok the phone picks each account from TikTok's mention list as it types, so a TikTok caption holds at most 5 mentions, uses@only to start one (no email addresses, no handle run into other letters such as@my-brand) and never names its own posting account, and a handle TikTok's list does not offer fails the post withmention_not_offeredbefore anything is posted (fix the handle withupdate_scheduled_post, thenretry_scheduled_post). An Instagram caption, a reel's or a carousel's, holds at most 2,200 characters and 5 hashtags: Instagram keeps no more than 5 hashtags on a post, so a longer list is refused rather than posted with the rest stripped to plain words. - •When the avatar has no account on a platform yet,
schedule_postwithawait_new_account=true(TikTok) orawait_new_instagram_account=true, orschedule_instagram_postwithawait_new_account=true, persists the post as waiting;purchase_account_seatswithlink_avatar_project_idthen 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. - •TikTok Shop. A TikTok account enrolled in TikTok Shop can link one product of its shop to each post, chosen per post (there is no default product).
get_tiktok_shopreads the shop as the account's phone last saw it (linked, the showcase, the catalog's products with their ids andshowcase_state);sync_tiktok_shopreads it again on the phone, which takes a few minutes. The account's daily phone visit also looks for the Shop tab and reads the shop by itself when the tab appears or goes, so an account TikTok enrolls shows up without a sync. Passtiktok_product_id(and optionallytiktok_product_link_name, at most 30 letters, numbers, spaces, apostrophes or hyphens) toschedule_postorupdate_scheduled_post;remove_tiktok_producttakes it off a pending or failed post, and a post moved to another account drops a product it does not restate. Only a video post links a product; a slideshow cannot. A post links from the showcase only, so a product not in it is queued for adding the moment the post is scheduled (add_tiktok_showcase_productsdoes the same on its own), and the post goes out only after the phone can have added it: an exact time before that is refused with statustiktok_product_not_in_showcase_yetandearliest_at_utc, and a date-only time is given a slot after it. The phone reads a product's title off the screen, so a long one reads cut short with … at its end;rename_tiktok_shop_productgives a product itsdisplay_title, the name to show for it (the phone keeps finding it by its title, and a read of the shop never changes the name). The phone reads each of the showcase and the catalog up to about 80 products; a list it could not read whole (longer than that, or with a product the phone saw but could not read) readsshowcase_completeorcatalog_completefalse, and the lists then hold part of the shop. The phone adds the link before its Post tap, and a post whose link cannot be added fails rather than go out without it. TikTok caps a new shop's shoppable videos (shoppable_videos_left, as the latest post that linked a product left it). - •AI label.
ai_label: trueonschedule_postlabels the video as AI-generated on every platform that call schedules (TikTok's "AI-generated content" label, and Instagram's "Add AI label" switch, which shows on the post as "AI info");schedule_instagram_posttakes it for the reel, andupdate_scheduled_postturns it on or off for one pending or failed post. TikTok and Instagram video posts only: a slideshow post and a Facebook post refuse it. The phone sets the label before its Post or Share tap, and a post it cannot label fails and is retried rather than go out unlabeled. Pamba cannot take the label off once the post is live, so set it only when the user asks. - •First-frame cover. Left alone, TikTok and Instagram pick a video's cover from a frame a few seconds in.
first_frame_cover: trueonschedule_postmakes the video's first frame, where its burned-in hook is, the cover on every platform that call schedules;schedule_instagram_posttakes it for the reel, andupdate_scheduled_postsets it (true) or leaves the cover to the platform again (false) for one pending or failed post. TikTok and Instagram video posts only: a slideshow post and a Facebook post refuse it. The phone sets the cover in the app's Edit cover before its Post or Share tap, and a post it cannot set it on fails and is retried rather than go out with another cover. - •If a schedule is rejected, read the reason and offer the valid accounts or another time; do not retry blind.
Slideshows
- •A slideshow is a TikTok photo post or an Instagram carousel (or, with
as_reel, one reel Instagram builds from the slides): up to twenty pictures with words burned in, and one sound per platform under the whole post: a TikTok sound for the photo post, an Instagram track for the Instagram post. It is made from pictures the workspace already holds — nothing about a slideshow spends credits, and there is no slide image generation. Get the pictures in first:upload_assetwith a public url (orlist_assetsfor ones already there), thencreate_slideshowwithslide_images(one Pamba-hosted url per slide, in order) andlines(write_with_ai=falsekeeps them verbatim; no lines gives picture-only slides). Both are strings: a JSON array serialised as a string, or one entry per line; the JSON array itself is taken too. A slide with a picture but no line has no text element. - •The tools are in the
contenttoolset (list_slideshows,get_slideshow,create_slideshow,update_slide,add_slide,remove_slide,reorder_slides,add_slide_image,update_slide_image,remove_slide_image,suggest_slide_lines,search_tiktok_sounds,set_slideshow_sound,search_instagram_audio,set_slideshow_instagram_sound,schedule_slideshow_post,get_slideshow_scheduled_post,duplicate_slideshow,export_slideshow,update_slideshow). Every edit re-burns the slide;get_slideshowreports each slide'sstatus(readyonce burned) and itsimage_url. - •Sound:
search_tiktok_soundswith noqueryreturns TikTok's Hot chart (sourcehot, in chart order, the editor's default listing); with aqueryit pages TikTok's own library (cursorfrom the previous page'snext_cursor), andset_slideshow_soundpicks one for the whole post bytiktok_music_id(the search result'smusic_id); the search is a plain read, not one of the capped AI assists. Searches that reach TikTok run at most 5 a second, 30 a minute and 1,000 a day per workspace (a repeat the day's cache answers is free); past that the tool answersrate_limitedwithretry_at(midnight UTC once the day's are used), and the REST route a 429 with aRetry-Afterheader. Every result carriescommerce_right: whether TikTok clears the sound for commercial use, which a Business account needs to post with it (its sound page shows no Use sound otherwise), so prefer a cleared sound for such an account. When TikTok's sound search or sound page is not answering,search_tiktok_sounds,set_slideshow_soundandset_video_tiktok_soundanswersearch_unavailable(nothing changed; try again in a minute) and the REST routes a 503. - •Instagram sound: the Instagram post's sound is picked apart from the TikTok one, because the two platforms' libraries are different.
search_instagram_audiowith noqueryreturns Instagram's Trending chart (sourcetop, read from a US account's picker); with aqueryit returns Instagram's own results for the words, ten at most with no further page, and the same per-workspace rate and daily limit as the TikTok search.set_slideshow_instagram_soundpicks one byinstagram_audio_id(the result'saudio_id;noneclears it). The track starts where Instagram's picker starts it (highlight_start_seconds), and the phone picks it in Instagram's own music picker when the Instagram post goes out. One it cannot find there goes out as the same song by the same artist at another length, else as a song Instagram picks, andget_scheduled_postandlist_scheduled_postsname it inaudio_fallback. The searches run on accounts outside the US, which list some songs US Instagram lacks, so a song a Pamba phone did not find, posting from an account Pamba knows is not a Business account (a Business account's picker lists only commercial music), is recorded and left out of every later search and of the chart. A pending or failed post still using such a song readsinstagram_song_unavailabletrue onget_scheduled_postandlist_scheduled_posts: set another song before it goes out to choose it yourself. A pick the chart or the day's searches did not list is looked up on Instagram's audio page, and that lookup counts against the same per-workspace rate as a search (not the daily limit, which counts searches only). No provider says which songs an Instagram Business account may use, so the whole library is listed. When Instagram's music search or audio page is not answering, the tool answerssearch_unavailableand the REST route a 503. - •Posting:
schedule_slideshow_postschedules the slides on a Pamba-managed iPhone and approves the slideshow; it is refused while any slide still has no picture. A TikTok photo post takes a single slide, and so does an Instagram post (platforminstagram or both), where one slide goes out as a single photo and two or more as a carousel; a reel built from the slides (as_reel) needs at least 2. Withplatformtiktok (the default:tiktok_username,scheduled_at,caption; the caption is the post's description, capped at TikTok's 4,000 characters with the same hashtag and mention rules as a video, and the post has no separate title) it is a public photo post carrying the slideshow's sound; withplatforminstagram (instagram_username, omitted when the avatar has one Instagram account;scheduled_at;caption, at most 2,200 characters and 5 hashtags, its@handles linked by Instagram) it is a public carousel carrying the slideshow's Instagram sound, each slide fitted whole into Instagram's square or 3:4 feed frame (square when the slides are square or wider), and it is refused until the slideshow has one (set_slideshow_instagram_sound): without a track Instagram does not treat the carousel as a reel and shows it only to followers, and the track cannot be cleared while an Instagram post waits;as_reel=trueposts it instead as one reel Instagram builds from the slides, each 4 seconds with the same track under it (which the reel needs too), in the full 9:16 frame with the first slide as its cover (refused withplatformtiktok; withplatformboth the TikTok photo post is unchanged); withplatformboth (tiktok_username, andinstagram_usernameas above) the two are booked together in one plan, both or neither, under onecaptionthat must pass both platforms' rules, and the result'spostslists each. A slideshow posts once per platform.get_slideshow_scheduled_postfollows them (postsholds one per platform:pending,in_progress,completed,failed), andcancel_scheduled_postwith a post's id cancels it while it is still pending. A TikTok photo post is verified against the account's profile and gets analytics like a video. An Instagram carousel is verified on the phone's word (the phone reads it as the profile's newest post), and the account's hourly analytics refresh then links it to its live post (posted_url, a/p/link) and tracks its likes and comments; Instagram publishes no views for a carousel. A slideshow's reel is verified the same way, then linked among the account's reels (a/reel/link) with its public views; each Instagram post inpostscarriesas_reel.
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 ofdiscard_wizard_scene,generate_wizard_scenes(fifteen credits a scene) andupdate_wizard_appearance(regenerates the look) beforeaccept_avatar_appearancelocks the appearance, thenselect_avatar_voice, which finishes the wizard.get_avatar_wizardpolls and already lists the freevoice_options;reroll_preset_voicesswaps in three other free picks (directionaccepts onlydeeperorhigher). 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 callgenerate_scene_variationson a fresh avatar. The first kept scene becomes the profile image. - •Voices are curated human recordings matched to the avatar's gender and age, all free (called "preset" in tool names for historical reasons). Each comes labeled by position,
Voice 1,Voice 2andVoice 3, the only name to give it.get_preset_voicesthenapply_preset_voicechanges an existing avatar's voice; browsing, rerolling and applying are free. There are no paid voices: an avatar that already has a premium voice keeps it. - •
update_avatar_settingsreplaces whole sets:tiktok_usernames,tagsandwarming_search_termsare 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. One exception keeps a new account from being dropped: a TikTok accountget_avatarlists withname_pending(its picked username is still being applied) stays linked while its rename runs and for an hour after it lands, whatever set you pass, and the set names it by its picked username;unlink_accountremoves it.default_video_modeltakesdefaultto clear back to the workspace routing rules. - •Scene library: every scene and library frame carries vision-derived
content_labelsfrom a fixed vocabulary plus ascene_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 withupdate_scene_frameauto-generates six pose variations (ninety credits) when it has none, andupload_scene_frameis stored active and does the same.delete_scene_framesalso 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_imageedits 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_variationkeeps that result as a variation (original untouched),replace_scene_imagepoints the frame at it instead, losing the original.promote_scene_variationswaps a variation with the scene's reference, so promoting it back undoes the swap. - •Camera styles are
selfie,tripod,tripod_full_body_visibleandpodcaston the avatar tools;generate_starting_framesspells the full-body styletripod_full_body, and the other spelling falls through to selfie there. - •
import_avatarcreates an avatar from a photo URL withgenderMALEorFEMALEand a free voice;redesign_avatarapplies free-form appearance or voice changes and blocks until they land.track_external_tiktok_accountattaches an account you post to from your own phone, for analytics only: posting and warming stay unavailable for it. A free workspace (signup credits only) can connect up to five such accounts; the sixth answersconnected_account_limit, and any plan, account seat or credit purchase lifts the limit. - •Operator-only tools are listed only to Pamba staff. A customer workspace or a connected chat app never sees them, and calling one by name is an unknown tool: the reference-frame tools (
create_reference_frame,update_reference_frame,delete_reference_frame),create_social_account,get_account_creation_status,resume_account_creation,generate_image, the writer-engine controls (run_content_engine,push_content_batch,apply_script_revision,set_script_starting_frame,decide_learning_item,set_autonomy_dial,set_batch_share_page,send_writer_chat_message), and the engine's spend bookkeeping (log_llm_usage, andget_llm_usage_summary, which reports the model spend at Pamba's cost).control_stage_runis listed to everyone, but cancelling a run, and retrying some runs, answersoperator_onlyfor a customer workspace.
Accounts, seats and devices
- •
list_accountsis 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), and, listed last, its old accounts: an archived account it held (one of its seats named it, or it posted from it) stays on the list, frozen and withon_devicefalse, after it leaves its phones, as an account a recreation replaced does. Status isposting,track_onlyorarchived; health flags includeBANNED,SHADOWBAN_RISK(after the account's first three weeks of tracking),NOT_RECOMMENDEDandSUSPENDED. - •
set_account_ordersaves the order the workspace's Accounts page lists accounts in, for everyone in the workspace, andlist_accountsreports each account'spositionin it. A save replaces the whole order, so moving one account means sending every account in its new place; accounts left out, and accounts added later, follow in the default order (open issues first, then the most viewed, a recreated account counting its seat's views so it keeps the row of the one it replaced), and under a saved order archived accounts are listed last. An empty list goes back to that default. - •Managed account seats cost one hundred dollars a month each, and every two of a platform get a phone of their own for that platform. A workspace whose owner signed up before the TikTok plus Instagram pair discount ended for new customers keeps it (
purchase_account_seatswith no seat counts returnsbundle_eligibletrue): every TikTok plus Instagram pair across the subscription prices its second account at fifty dollars, re-priced when seats are added or cancelled. Every other workspace pays one hundred dollars for every seat, and itsunpaired_seatsis empty. From Monday, November 16, 2026 at midnight Pacific no new seat pairs:bundle_eligible, which says whether the seats bought now pair, is false andunpaired_seatsis empty unless Pamba agreed a different price with you, so every seat bought from then on is one hundred dollars a month. The price of the seats you have is onget_seat_billingand each account in the inventory, neverbundle_eligible. Seats bought before then keep their pair price for as long as both seats of the pair bill, an account recreated on its seat or a seat the Pamba team moved to another card included; a seat cancelled and bought again is a new seat at one hundred dollars. Until then, for a workspace with the discount, a paid purchase also pairs with seats already on the subscription it raises, the newest one that is active and not set to cancel:purchase_account_seatscalled with no seat counts returnsunpaired_seats, per platform the seats on that subscription with no partner yet, and the next paid purchase pairs up to that many seats of the other platform with them. One Instagram seat next to one unpaired TikTok adds fifty dollars a month, not one hundred; two Instagram seats next to it add one hundred fifty. Only whatunpaired_seatslists pairs this way: an account with no seat, a seat on a free-seat grant (free_seats_remaining) or on another subscription, and a seat cancelled withcancel_account_seat(even while it posts until its period ends) pair with nothing, and when no subscription can be raised, the purchase starts a new one where only its own seats pair. 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. While Pamba's phones are short of room for new accounts,purchase_account_seatsreturnshigh_demandtrue and every checkout it creates carrieshigh_demand_notice, whatever its seats: new accounts may take up to 5 days to be created (for purposeconnect, the accounts may wait up to 5 days for a phone to sign in on), and the user hears so before paying. Facebook is an add-on to an Instagram account: a flat one hundred dollars a month on top of its Instagram seat that never pairs (Instagram with Facebook is two hundred dollars a month, a TikTok plus Instagram pair with Facebook three hundred, or two hundred fifty with the pair discount). It is rolling out:purchase_account_seatscalled with no seat counts returnsfacebook_addon_offer, none or with_new_accounts.facebook_for_instagramadds it to Instagram accounts the workspace already has: only one Pamba created, whoselist_accountsrow readsfacebook_addon_eligibletrue (facebook_addon_refusalsays why not), all paid on one card, and for now each phone takes one, so rows with the samefacebook_addon_phone_groupare a choice of one.facebook_seatsadds it to the order's new Instagram accounts, at most one each and for now one per phone they fill (facebook_addon_unusable_slots, a refusal says how many; an order that also namesfacebook_for_instagramcounts those accounts' phones as taken, so it can take fewer), and an order to connect takes no Facebook. Both go in one order, andpurchase_account_seatscalled with no seat counts lists the accounts that can take it now asfacebook_addon_accounts, each with itsphone_group. A post scheduled ahead of the purchase (await_new_instagram_account) whose order takesfacebook_seatswaits for that Facebook account too, so its reel goes to both. The Facebook account is created from its Instagram account, with the same name, birthday and, when Facebook allows, handle, and its Instagram reels cross-post to it.purchase_account_seatsreturns a checkout URL: a purchase that raises an existing subscription gets Stripe's confirm page raising its quantity with proration, and one that starts a new subscription gets a new checkout. When Stripe cannot list the workspace's seat subscriptions or open the confirm page, the tool answerspurchase_unavailablewith a message to try again, and nothing is charged or started. A checkout paid by bank transfer completes before its payment clears (usually up to four business days): until then its seats are listed underwaiting_for_payment, nothing is created for them, and they move tobeing_set_uponce Stripe confirms the payment; a payment that fails drops them. Do not buy again while seats are waiting for their payment. - •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 with
reassign_accountand nofrom_avatar_project_id(TikTok or Instagram; no password, no phone work). The same tool moves an assigned account whenfrom_avatar_project_idnames its current avatar; without it an assigned account is never moved. A TikTok or Instagram account can post for several avatars (a Facebook account follows its Instagram account):link_account_to_avataradds one without taking the account from the others, so a video for a second avatar can go to an account the first one already uses instead of a new purchase.unlink_accountis the reverse: it drops one avatar's binding, and an account no other avatar links is a spare again, still signed in on its phone, with its status and history. - •A bought seat waits for its username before creation starts.
suggest_account_usernamesreturns a checked, currently free idea per waiting seat (names for a waiting order are prepared in the background, so a call usually answers at once; otherwise a few seconds each, so for a large order passbatch_size, for example 8, and call again withexcludeset to the names already offered; a batch answers within 90 seconds),check_account_usernameverifies a pick (availability is a hint, not a reservation),set_account_usernamesaves it and starts that seat's creation, oruse_default_name=truecreates with a platform default. The account's name goes with the pick: withdisplay_name_from_username=true(the app's default; leave it out to keep TikTok's own) a TikTok account's display name is set to the username it ends up with, in its own edit once the rename lands, which spends TikTok's one display-name change per 7 days; an Instagram account is created underfirst_nameandlast_name(30 characters together at most).suggest_account_usernamesoffers each Instagram seat a name with its username, the linked avatar's or else the username's first name (Claire forwanderwithclaire) with a surname picked for it, andcheck_account_usernameshows that name for any Instagram handle. A seat saved without a name is created under the avatar's name (a one-word one with a surname drawn at signup), else its username's, else (no username) a generated one, so pass an offered name back with the username it came with to keep it, and never send a typed handle's name on a seat linked to an avatar. An account made on a phone that already holds an Instagram account, where Instagram asks for no name at signup, gets a name given for it (an offered one sent back included) or its avatar's about three days after it is made, a name changed in the meantime winning, and no name otherwise. 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; until the rename lands (usually a few minutes) the account stays offlist_accounts'accounts, listed underaccounts_being_namedwith its pick, and its seat shows inpurchase_account_seats'being_set_upat stageapplying_username. A name that fails when applied falls back to close variations, then keeps the platform handle; the account-ready email and Home item then say which pick was not used, andlist_accountscarries it aspicked_username_not_appliedfor thirty days or until the account is renamed. Progress shows per account onlist_accountsuntil the account is ready. - •
cancel_account_seatkeeps the account posting until the paid period ends, then stops posting and billing, no refund;reinstate_account_seatundoes it before that date at no cost, the seat billing again from the next renewal; a seat subscription cancelled on Stripe's billing page renews with it, its other seats included. Cancelling an Instagram seat cancels its Facebook add-on with it, on the same date, and reinstating it brings the add-on back; a Facebook add-on can be cancelled on its own, and reinstated on its own only while its Instagram seat is kept. An Instagram account with a Facebook add-on can't be recreated for now (has_facebook_addon). Once a workspace holds no seats, the phones its seats came with are signed out and returned to the pool three days after its last seat subscription ends, even while a credit plan runs. When a whole seat subscription ends (its seats cancelled, or Stripe gave up on a failed payment), its accounts stop posting at once but stay on their phone for those three days:get_seat_billinglists them underrestore_offers, andrestore_account_seatsreturns a checkout that brings them all back at the price that subscription billed (an account the workspace had paused itself comes back paused); after that, resubscribing can't bring them back. An offer'spayment_failedis true when Stripe ended the subscription because its renewal payment didn't go through; Pamba then voids that subscription's unpaid invoices, so the old bill can't be paid for nothing.get_seat_billingshows the next renewal's total per seat.recreate_social_accountreplaces a seat-funded Instagram account with a new one on the same seat, on its phone unless that phone takes no new accounts, when the new account goes on another of the workspace's phones or a new one (once every 10 days per seat, admins only; the old account keeps counting in the workspace's analytics with nothing new read for it, flaggedarchived, its videos are not deleted and Pamba keeps its credentials in case they are ever needed; its pending posts move to the new account, or withmove_scheduled_posts: falseare cancelled when the new account lands and their videos stay to schedule again);get_account_recreationsays whether an account can be recreated now and how a recreation is going. A TikTok account cannot be recreated by the workspace (unsupported_platform) unless TikTok banned it and it carries the freereplacement_offerbelow: otherwise only Pamba's team replaces one. While any recreation runs,list_accountsleaves the old account out and lists it underrecreations_in_flight. - •
import_social_accountbrings a TikTok or Instagram account the user already owns onto Pamba: a seat still waiting for an account takes it at the normal seat price, one bought to connect before one bought to create (no_open_seatmeans buy seats withpurchase_account_seatsand purposeconnectfirst: the same prices and pair discount, no usernames asked, and each seat waits inbeing_set_up, purposeconnect, until an import fills it, so ten accounts are paid for once and connected one by one, whenever the user is ready), and one of the workspace's phones signs it in with the handle, password and, when it is not the handle, the email or phone the user signs in with. Accounts that sign in only with Google or Apple need a password set in the app first. The sign-in usually stops on a verification code the platform sends the user: pollget_account_import_statusevery few seconds, and the moment itscode_requestis set (kindemail, sms, authenticator or approve_on_device, the maskeddestination,wrong_codeafter a refused code,expires_at) ask the user for the code and pass it tosubmit_account_import_code; codes expire within minutes, andresend_account_import_codeasks the phone to send a new one (afterresend_available_at: the apps hold their own resend about a minute). For an email or text code the app also asks on the user's own phone whether the sign-in is theirs, and approving there works with no code.password_rejectedtrue means the app said the password was wrong and sent the code to an address it chose: the user enters it only if the address is theirs, and if it is not, the handle reached someone else's account (cancel_account_importand start again with the right handle, or, once the code wait ends and the import readsneeds_customer,retry_account_importwith the rightusername).needs_customercarries afailurethe user must fix (a wrong password, a code never given, too many tries, a suspended account, orpasskey_required: TikTok only lets the account in with a passkey on the user's own phone, which they remove in TikTok under Settings and privacy, Account, Passkey; orapprove_on_device: the app asked them to approve the sign-in on their own phone, so they retry when that phone is with them and approve it there), thenretry_account_importwith the new password, login or handle (username: a mistyped handle readsaccount_not_found; a retry after five sign-in attempts hands the import to Pamba's team instead).failure.codewrong_accountmeans the user's login opened another of their accounts, named inopened_username, which the phone has already signed back out: ask whether it is the one they meant, and if soretry_account_importwithusernameset to it (the same login and password), otherwise with theusernameand login of the account they meant (a reconnect leavesopened_usernameempty and keeps its handle);with_teammeans Pamba's team is finishing the sign-in by hand and settles any code it needs with the user directly, or hands it back asneeds_customerwhen only the user can move it on.cancel_account_importstops an import and frees its seat; a reconnect is refused (reconnect_not_cancellable) while its account still fills its seat, and Pamba closes one 3 days after its seat ended, when the seat can no longer be bought back. Pamba changes nothing on an imported account by itself (no AI-comment filter, no AI-creator label, no rename); it warms like every account on a phone. If TikTok or Instagram later signs it out of its phone (a password change, or the app ending its session), its import reopens asneeds_customerwithfailure.codesigned_outand the user is emailed: untilretry_account_importreconnects it (the stored password unless the user gives a new one, then the code the app sends, as on the first connect) it can't post or warm,schedule_post,schedule_instagram_post,schedule_slideshow_post,post_instagram_storyandpost_tiktok_storyrefuse it withaccount_needs_reconnect, its scheduled posts fail with that code (retry them once it is reconnected), andlist_announcementsleads with a warning (kindwarning, labelSigned out) naming it. An import connects only the account it names: Instagram also signs in every account that shares a Meta Accounts Center with it, and Pamba never lists, warms or posts from those; connecting one takes its own seat and import. - •A workspace that only buys accounts and posts its own videos runs this order, and nothing in it spends credits:
list_accountsto rule out a spare,purchase_account_seats(passlink_avatar_project_idwhen the account is for an avatar) and the person pays at the checkout URL,suggest_account_usernamesthenset_account_usernameper seat (creation starts only once a seat has a name),list_accountsuntil the account readsposting, thencreate_draft_project,set_edited_videoandschedule_postwith the new username (see Scheduling and posting). To queue the post before the account exists, the project needs the avatar the purchase links to, andschedule_posttakesawait_new_account=truein place of a username. - •
follow_accountshas a TikTok or Instagram account on a Pamba phone follow a list of usernames or profile links. An account's lists keep to a daily limit, because TikTok and Instagram can flag an account that follows too much: none in its first seven days on a Pamba phone (counted from its first warming session or follow list), so the first follow lands once the account is a week old, then one a day at most, however old the account. Warming's own follows are separate and do not count toward it.get_account_followsreports the limit today asdaily_limit(withstarts_at_utcwhile a new account's first days last). A list waits for the limit, and a waiting list's next session time says when it continues. The phone follows one account per session, at a different time each day between 8 AM and 1 AM Pacific, around the account's posts and warming, and at most fifty wait at once; a session that followed no one (already followed, not found) leaves the day's follow for the next session, at least three hours later (up to half an hour more). A request while a list is running joins it (up to a hundred accounts on one list in all; a list being stopped takes nothing new, so the request opens the next list), and a new list starts no sooner than three hours after the account's last session. A profile the account already follows is left alone, and the account never follows itself. It runs in the background:get_account_followsshows the running list with each account's outcome (followed,requestedfor a private account,already_following,not_found,failed(where a mistyped or deleted username usually lands, with a reason to check it),cancelledwhen a stop reached it first, orskippedwhen the request failed before reaching it), andcancel_account_followsstops what is still waiting; a session already on the phone finishes its one account first. - •
delete_account_postsdeletes published posts from an account on a Pamba phone, videos and slideshows alike (TikTok videos and photo posts; Instagram reels, carousels and pictures), up to twenty per request and fifty waiting per account: it removes them from the platform itself, so confirm the exact posts first. Name each by itspost_idor by its link: a project'sposted_tiktok_video_urlorposted_instagram_video_urldeletes that project's post, and a slideshow post's posted link deletes that slideshow post.list_account_postslists the account's posts newest first with each one'spost_id, itskind(video,slideshoworpicture) and its deletion state (pending,deleting,deleted,not_foundwhen the post was already gone,not_confirmedwhen the phone could not prove the post on screen was the one asked for and deleted nothing,delete_unconfirmedwhen the phone may have deleted it but its link did not show it gone (the delete was confirmed, or the post was in a session nobody heard back from), which is not final: Pamba checks the account's own listing about fifteen minutes after the session and settles the postdeletedonce the account no longer lists it, orfailedwhen it still shows it (a post the listing cannot see, such as an Only-you TikTok post or an Instagram reel off the profile grid, is settled by Pamba's team instead),failed,cancelledorskipped). A post the phone reporteddeletedthat the account still lists on both checks turnsfailedtoo. The phone deletes five per session, around the account's posts and warming; TikTok and Instagram keep a deleted post 30 days in Recently deleted, where only someone on the phone can restore it. Withpost_ids(ids or links) it returns only those posts, and still returns a deleted post the platform no longer lists, with its state.cancel_post_deletionstops what is still waiting; a session already on the phone finishes its own few first. In the app it is Delete from TikTok or Delete from Instagram on a posted post (the project's More menu, and the post's row and calendar card on the Schedule page, slideshow posts included). - •
list_commentslists the comments on the workspace's own TikTok and Instagram videos from the last sixty days (only the accounts it pays for, on its Pamba phones or under a live seat; an account it only tracks for analytics has none), each top-level comment with its replies and its video: newest thread first, or withsortthe most liked first (most_liked) or in the order TikTok or Instagram itself ranks the video's comments as of Pamba's last read (top). Comments are read about every fifteen minutes once a video's comment count grows, so a new one shows within about an hour;checked_atis when Pamba last checked the accounts' videos for new comments,synced_atwhen it last read one of the listed videos.hidden_by_platformmarks a comment Instagram hides under "See hidden comments", and the replies under it: replying to it, liking, pinning or deleting it is refused (comment_hidden), since the phones never find it there, and comment automations skip it.questions_only=truekeeps the comments that ask the creator something or ask for something the video offered,mine=truekeeps the threads the workspace's accounts took part in, andqsearches the text, the authors and the replies.about_aimarks a comment that says or asks whether the video or the person in it is AI or not real, and each TikTok account on the workspace's phones carriesai_comment_block_stateandauto_block_ai_comments: when such comments sit on an account whose filter isfailed, oroffwithauto_block_ai_commentstrue (false means the user allowed AI comments),update_account_profilewithdisable_ai_commentsandauto_block_ai_commentsboth true turns on TikTok's filter for them, as the Comments tab's Block AI comments line does.list_comment_videosgives the same comments per video, newest activity first, with how many match and how many are questions, for going through them one video at a time; it also lists every post from the last seven days before its first comment, so the account can leave that first comment withcomment_on_video.reply_to_commentanswers a top-level comment andcomment_on_videoadds a new comment to one of the workspace's own videos, from any of the workspace's accounts on that platform (account, the video's own by default); either is typed within minutes on that account's phone, or atscheduled_for(an ISO-8601 time with its offset, from a minute to thirty days ahead), so only an account on the workspace's phones can send (theaccountslist says whichcan_reply), up to one hundred fifty characters on TikTok and two thousand two hundred on Instagram, and at most thirty in any rolling day per account. On TikTok an @username in the text is picked from TikTok's own list as the phone types it, so it posts as a tappable mention showing that account's display name; a username TikTok does not offer fails the comment unsent (failed, with a reason naming it), since typed as it is it would not link. Instagram links a typed @username by itself. TikTok and Instagram lock an account that comments on other accounts' videos too early or too often for suspicious activity, so on another account's video (another of the workspace's), an account Pamba created comments only after its first seven days (statusnew_account), and any account at most the workspace'scross_account_per_dayin any rolling day (one unless the Pamba team raised it;cross_account_daily_limit); each account inaccountsthat can reply carriescross_account_blocked_reasonandcross_account_available_atwhile it is held, and its own videos are never held. Two accounts signed in on the same phone never comment on each other's videos, nor reply to or like a comment on them or one the other wrote (same_phone, at any time); each account'sphone_matesnames the accounts on its phone. A comment, reply or like that reaches the phone anyway, because the two came to share a phone after it was asked for, is cancelled before it is sent, itsstatus_detailsaying why. Every limit counts at the time the comment goes out, against the account's comments before and after it, so a refusal'savailable_atpassed asscheduled_forqueues it, and a workspace spreads comments across days by scheduling them. What an account is asked to do now on one video, comments, replies, likes, pins and deletes alike, goes out together in one phone session, as a creator does it in one sitting: each request waits two minutes for the next, the run goes out at most ten minutes after its first, and a session takes up to ten; requests givenscheduled_forgo out at their own times, so the same time groups them and different times keep them apart.comment_on_videowithpintrue has an Instagram reel's own account pin the new comment once it is live.like_commentlikes a top-level comment from one of the workspace's accounts (the video's own by default on its own videos) andpin_commentpins one on the workspace's own Instagram reel from the reel's account (Instagram keeps up to two pinned comments per post; TikTok no longer lets creators pin comments,pin_not_available), anddelete_commentdeletes a comment or a reply from the workspace's own TikTok video or Instagram reel through the video's own account (only a video's owner can delete other people's comments on it, so never on a video the workspace added,delete_not_allowed; nor a comment with no words of their own (only a sticker, photo, GIF, @mentions or punctuation), or a reply under such a comment,not_deletable; it cannot be undone, a comment's replies go with it, it withdraws the workspace's queued replies, likes and pins of the comment and deletes of its replies, and the comment takes no more while the delete is on its way,comment_being_deleted, also the answer for a reply whose comment is being deleted; a reply's delete shows in its thread'sreply_actions, and once the phone saw the comment gonelist_commentsno longer lists it); all three are typed on the phone like a comment, likes and pins now or atscheduled_forand a delete now, thirty a day per account together, never counted against the comment limits; a like from an account that does not own the video (another of the workspace's accounts' videos) keeps to the workspace'scross_account_likes_per_dayin any rolling day (one unless the Pamba team raised it;cross_account_daily_limit, withavailable_at), each account inaccountscarryingcross_account_like_blocked_reasonandcross_account_like_available_atwhile it is held, so likes in bulk are spread across days by giving each itsscheduled_for; andlist_commentsshows them in each thread'sactions(list_outgoing_commentslists them withactionlike, pin or delete; it lists comments alone by default). To reply in advance, passreply_to_commentthe outgoing id of one of the workspace's own comments that is not live yet: the reply waits for it, and up to three replies can wait behind one comment, going out one at a time in the order they were asked for, each once the one before it is live and fifteen to forty-five minutes after it was sent (reply_to_outgoing_idnames the comment it answers andwaiting_for_idthe one it waits for). Once a comment has replies in advance behind it (on their way or live), another reply to it, by its outgoing id or by its comment id once it is live, joins the end of that line. If a comment before them fails, is cancelled or still does not show two days after it was sent, the replies behind it are cancelled too; a fourth reply answerschain_full, and a reply to a comment that will not go live answersparent_not_live.list_outgoing_commentsfollows each one:queued,sending,posted(the phone sent it, or Pamba lost the phone's answer; a read of the video settles which),liveonce a read of the video shows it,not_visiblewhen no read has six hours later, orfailed;cancel_outgoing_commentwithdraws one while it is still queued, with the replies waiting behind it. - •
create_comment_automationanswers comments by direct message: when someone comments one of itskeywordson one of the workspace's TikTok or Instagram videos (itsaccounts, or withall_accountsevery account on the workspace's phones, those added later included; every post), the account's phone reaches them from their comment (it opens the post, finds the comment and taps their name) and sends themdm_text, a first message with no link that asks them to reply (a link in it is refused,link_in_first_message), once per person; once they reply yes (or anything that says they want it), within seven days, the phone sendsfollow_up_text, the message with the link (required,follow_up_required; a few words with the link: one that is only a link is refused). Instagram shows a link to someone who does not follow the account only after they reply, and waiting for a reply keeps the account from looking like spam. Then, in the same visit, replies under the comment with one of itsreply_variants, orfallback_replywhen the person's settings refuse the message (a reply counts toward the account's thirty comments a day; one the comment queue refuses is left out). A keyword matches as whole words, ignoring capitals, accents, punctuation and emoji (match_modeexact: the comment is the word and nothing else), and{username}in the message or a reply becomes the commenter's @handle. Each account sends up to twenty first messages a day, spread out through the day (list_comment_automationsreports the limit asdaily_dm_limit; the messages with the link do not count toward it), on TikTok the oldest comment first and on Instagram each post's newest waiting comment first, the posts taking turns (a comment the phone cannot find endsnot_sent,comment_not_found, and does not count toward the limit); a TikTok message goes out as one paragraph. It is on at once (enabledfalse: created off) and also answers matching comments from the last seven days unlessanswer_recent_commentsis false; no automation answers a comment older than seven days, or one by the workspace's own accounts.update_comment_automationchanges any field and turns it off or on (enabled); turned back on, or set to answer other comments (its keywords, match mode or accounts), it answers only comments made from then on, and a newdm_textorfollow_up_textgoes to the messages and people still waiting too; while it is off, the links of people who said yes wait as well. An automation that is off can have nofollow_up_text(one saved before the two messages whose message had no link to send second): turning it on needsfollow_up_text. Two automations that are on cannot share a keyword on one account (keyword_in_use), and a comment that says the words of two of them gets one message, the older automation's.list_comment_automationslists them with their last seven days and the accounts that can send;list_comment_automation_activitylists every comment one answered and its message's status (queuedwithnext_attempt_atwhile it waits for the daily limit or the account's next session,sending,sent,not_sentwith why,skippedfor someone already messaged or, on Instagram, a commenter whose profile is private (no message is tried, it does not count towarddaily_dm_limit, and the comment getsfallback_reply), or a comment Instagram hides (comment_hidden: the phone never finds it, so nothing is sent),cancelledwhen the account's seat ended) and, once the first message went out, where the link stands (follow_up_status:waitingfor their yes,sent,not_sent,no_reply,cancelled, withfollow_up_detail;replied_atis their yes), andlist_commentsmarks each answered comment in its thread'sautomations.delete_comment_automationdeletes one; its waiting messages and links are not sent, and what it sent still counts toward the account's daily limit. - •
update_account_profileedits 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. On TikTok the phone picks each @handle in a bio from TikTok's mention suggestions, so it lands as a tappable mention that TikTok shows as @ and that account's display name; a handle TikTok offers no account for fails the bio field with the error code bio_mention_not_found, and a mention the phone could not show links the account asked for (a pick on a suggestion whose caption TikTok cut short, or a bio TikTok already held whose mentions are not drawn as links) with bio_mention_unconfirmed; an email address stays text.list_accountsreports each account's current bio, whichever is newer of the one Pamba last set and the one last read off the phone (on TikTok, a read that is the bio Pamba set with each mention shown as @ and a display name still reports the bio as set, with the handles an edit sends again); 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. On TikTok the phone gets time for each field and each @handle an edit asks for; a field it had no time left to start comes back not applied with the error code field_out_of_time, beside the fields it did apply. An Instagram bio with a link, put on an account Pamba created less than seven days ago, still goes through, and the result carries awarning: Instagram often restricts link sharing on accounts that add a link this early. Aqueuedanswer, from this tool or fromenable_instagram_ai_creatoranddisable_instagram_ai_creator, carries the edit'sjob_id, whichget_account_profile_editreads to its outcome. - •
update_account_profilealso switches an Instagram account between personal and creator withinstagram_account_type, sets its profile category withinstagram_category(any case, one of Digital creator, Artist, Musician/band, Blogger, Clothing (Brand), Community, Education, Entrepreneur, Health/beauty, Writer, Personal blog, Product/service, Gamer, Restaurant, "Beauty, cosmetic & personal care", Grocery Store, Photographer, Shopping & retail, Reel creator, Gaming video creator, Social Media Agency, Camera/photo, Computer Company, Makeup Artist or Creator) and whether the profile shows it withinstagram_show_category, sent in a call of their own with no other field: the account type is its own job on the phone, answeredqueuedwith ajob_idthatget_account_profile_editreads (its kind is instagram_account_type, its fields account type, category and show category). Pamba never switches an account to business, since Business accounts can't use most of Instagram's licensed music:businessis refused with the error code instagram_account_type_invalid, and an account that is a Business account already is never switched to creator (instagram_account_business) but can go to personal or change its category; when the phone finds a Business account Pamba had not read yet, the job fails with ig_account_business and nothing changes.creatoron an account that is creator or business while its switch to personal still waits for the phone, never yet sent to it, withdraws that switch instead: the call answerswithdrawnwithwithdrawn_job_idsand the account stays as it is (a category or display in the same call is queued as its own change); a switch to personal already sent to the phone is refused with change_in_progress, and on a creator account after an earlier type switch of it ended unread the call is queued over the waiting switch instead (it answersqueued), for the phone to read the type the account has. A personal account, or onelist_accountsgives noinstagram_account_typefor, switched to creator takes the category Digital creator unless the call (or a change already queued) names one, and a hidden display unless it names one; an account that is creator or business already changes only the fields the call names. A category or its display alone needs an account that is creator or business, or has a switch to creator queued (one Pamba knows is personal, or with a switch to personal queued, is refused with the error code instagram_account_not_professional; one whose type Pamba has not read goes to the phone, whose job fails with ig_account_not_professional when the account is personal), a category Pamba does not offer answers instagram_category_invalid with the list, and a call for TikTok is refused, since TikTok's only switch is to a Business account, which limits it to TikTok's commercial music library. Switching makes the profile public, and Instagram also turns on stricter filtering for professional accounts, which hides more comments and message requests; going back to personal turns its insights off.list_accountsreports each Instagram account'sinstagram_account_type,instagram_categoryandinstagram_show_category, the newer of what Pamba last set and what the hourly analytics refresh last read. Instagram trial reels need a creator or business account with at least two hundred followers. - •
update_account_profilealso keeps a Creator or Business Instagram account's audience in chosen countries withinstagram_audience_countries, in a call of its own:us_only,tier1(the US, Canada, the UK, Australia, New Zealand, Ireland, Singapore and Western Europe),tier1_tier2(adds Central, Southern and Baltic Europe, Japan, South Korea, Israel, the Gulf, Hong Kong and Taiwan) orallto clear it. It works through Instagram's Minimum age setting: outside the chosen countries Instagram shows the account only to people it knows are 25 or older, so it does not block a country. A personal account is refused withinstagram_account_not_professional. The change is its own job on the phone, answeredqueuedwith ajob_idthatget_account_profile_editreads (its kind is instagram_audience_countries, its field minimum_age, whose applied value is the choice the phone read back); it takes a few minutes forus_only. Instagram takes only about 15 such changes a day on an account, so a bigger change continues by itself the next day (tier1_tier2from scratch takes three days); between runs the job reads queued, and a choice sent meanwhile joins it.list_accountsreports the account'sinstagram_audience_countries,customwhen it was set by hand in Instagram, and none after a change that failed partway, until the next change reads the page again. - •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_commentsturns it off per account.get_avatarreports the state per account asapplied,queued,scheduled,failedoroff, and null when the account is not on one of the workspace's phones. - •
enable_instagram_ai_creatoranddisable_instagram_ai_creatorturn the label on and off; each leaves a label already where it asks untouched, and a change still queued for a busy phone takes the newest call's direction. While the phone is applying one direction, a call for the other is refused withchange_in_progress; call again once it settles.list_accountsreports each Instagram account'sai_creator_label_state:turning_onorturning_offwhile the phone is queued or running to change it, thenonoroff,failedwhen the newest attempt to turn it on failed, orturn_off_failedwhen the newest attempt to turn it off failed (the label is still on); each TikTok account carries its AI-comment filter asai_comment_block_state. Both are empty for an account on none of the workspace's phones. - •Warming (human-like browsing on the account's phone, so it reads as a real person before and between posts) is always on for every device-hosted account and cannot be turned off from the tools; Pamba sets its pace, which is not configurable. Every account warms under its own config (
get_account_warming_config,set_account_warming_search_terms), whichever avatars link it. An avatar's config (get_warming_config, terms viaupdate_avatar_settings) is the one its accounts start from: an edit there is written onto every account the avatar links, shared ones included, and an account linked to its first avatar takes that avatar's settings. A linked account warms while every link of it posts and at least one linking avatar is active. Search terms steer what warming looks for. Terms cap at twenty-five of eighty characters, and a save carrying a term with "porn" is refused with a message naming it, since TikTok and Instagram show no results for it; without explicit terms, sessions fall back to terms generated from the workspace niche (search_terms_sourceniche), while an empty list saved withuse_niche_termsfalse is kept as the owner's own and its sessions search nothing (search_terms_sourcenone;use_niche_termstrue with an empty list goes back to the niche terms). A term TikTok answers with its guidelines page on the phone leaves the account's terms, the terms of the avatars linking it and of every account those avatars link, and the niche terms by itself, and the workspace gets a Home item at once and an email about two hours later; a "No results found" on either app removes nothing. The workspace's defaults, which a new avatar and a new TikTok or Instagram account with no avatar start with (an account added to an avatar takes the avatar's setting), areupdate_workspace_settingswarming_searchesandwarming_follows(list_workspacesreports both); either needsapply_warming_to_existing_accounts: true also writes it onto every existing account and avatar, false changes the default for new ones only, and without it the call changes nothing and answersneeds_choice. Warming keeps running either way.set_account_warming_switchessets one account's own switches:follows_enabledfalse and its sessions follow no one,searches_enabledfalse and they never search while its terms are kept for when searches are back on;get_account_warming_configreports both.update_avatar_settingswithwarming_searches_enabledorwarming_follows_enabledsets them for every account an avatar links, shared ones included, and for an account it links later that no other avatar links;get_warming_configreports what the avatar's last edit set, as it does its terms. An Instagram account's Cross-post reels to Facebook switch rides the same config and is set two ways, with no workspace default (a new account starts on):set_account_facebook_cross_postingfor one account,update_avatar_settings'facebook_cross_post_enabledfor an avatar's Instagram accounts;get_account_warming_configandget_warming_configreport it asfacebook_cross_post_enabled.cancel_warming_sessionworks only on pending sessions.get_account_activityis one feed per account of what the phone did for it, newest first: warming sessions (status, length, videos watched, likes, comment reads, creators followed, the search term, a few sample screenshot URLs), daily TikTok health checks, posts, profile edits, finished follow requests and post deletions, and the comments and replies the account posted with every screenshot the phone took of each; pass a page'snext_beforeback asbeforeto read further back, and an emptynext_beforeends the feed. - •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 and surfaced on Home, and emailed to the workspace about two hours later; these kinds never pause the account.get_tiktok_account_healthreturns the latest screenshots and open issues with each appeal's progress;request_tiktok_appealrecords the decision to appeal a removed or restricted video or an account warning, one appeal per issue, and nothing is appealed without it unless the account's auto-appeal is on (set_tiktok_auto_appeal, reported byget_tiktok_account_healthasauto_appeal): then every open issue is appealed when it goes on, and each new one as the daily check finds it. The account's phone then files the appeal itself, submitting only once a TikTok screen prints that video's posted time (a video it cannot pin down is filed by the Pamba team by hand; anACCOUNT_WARNINGis appealed through the video TikTok removed with it: appealing it also appeals the one removed video the same daily check found, and one verdict decides both; with none or several, the Pamba team files it by hand), and reads TikTok's verdict off the account's notifications once a day until it answers:appeal_verdictAPPROVED closes the issue as restored, REJECTED keeps it open. An appeal TikTok has not answered four days after filing sends the phone back to the video to read TikTok's answer on its page. A removed video reappearing also closes its issue and approves its appeal, a video the phone finds no longer restricted when it goes to file closes its issue as restored, other issues close after two clean daily checks, except one whose appeal is still being filed or still waits for TikTok's verdict (up to 21 days after filing). A video the workspace deletes through Pamba (delete_account_posts) takes the open issues that predate the deletion with it once the deletion confirms it gone (closed asDELETED): its appeal stops wherever it stood, and nothing is filed, read or rechecked for it. AnACCOUNT_WARNINGTikTok gave for that video stays open; if its appeal was not filed yet, the Pamba team checks whether TikTok still takes it. When Pamba replaces an account with a new one, every open issue of the old account closes (closed_byMANUAL) and its appeals stop.close_account_incidentdismisses an issue for good. - •Accounts suspended by Meta open a
SUSPENDEDincident that stops Pamba's warming, daily reads and posting on the account until the incident is closed withclose_account_incident, only after the account is verified restored: its warming sessions are cancelled, its pending posts fail saying why, and every new post, retry, profile edit, comment or other request on it is refused, as on an account TikTok or Instagram banned (below). A suspended Instagram account is signed out of its phone, so Meta's page stops blocking the phone's other accounts: it stays listed on its phone and is signed back in once its incident is closed. Its phone then takes no new Instagram account (a banned account's phone takes no new account of its platform either), sorecreate_social_accountrefuses the suspended or banned account itself withphone_on_hold(Pamba's team replaces it on another phone) and makes the new account of any other Instagram account on that phone on another phone: another of the workspace's phones with room, else a new one, the old account staying where it is. One exception: an Instagram account suspended by Meta, or asked by Instagram for identity verification with a video selfie (anIDENTITY_VERIFICATIONhealth flag, its incident'serror_codeig_identity_verification), after its first day can be replaced for free, and so can a TikTok account TikTok banned after its first day (its new account goes on a phone that never hosted an account).get_account_recreationandlist_accountsreport it asreplacement_offer, andrecreate_social_accountthen takes it with no cooldown and makes the new account on a new phone (suggest_account_usernameswithreplacing_platformandreplacing_usernameoffers free usernames for it; a seat gets one free replacement a month, and without an offer the account is the team's to replace;posts_start_after_daysstarts the moved posts at least a few days after the new account is ready, each at its own time of day). An account Pamba confirmed TikTok or Instagram banned carries aBANNEDhealth flag and incident (a TikTok ban about an hour after Pamba finds it, before which its work waits): it takes nothing more, its pending posts fail saying why and every new post, retry, profile edit, comment or other request on it is refused, so schedule its videos again on another account or the new one; a TikTok one past its first day carries that freereplacement_offerfor the user to take, otherwise Pamba replaces it with a new account on its seat at no extra cost, and only Pamba closes the incident (close_account_incidentanswerspamba_closes), withclosed_byRESTOREDwhen the account comes back orMANUALonce a new account replaces it. While any account is banned,list_announcementsleads with a warning (kindwarning, labelBanned) naming them, the strip shown across the top of the app; aSigned outwarning about accounts to reconnect comes after it. A ban outranks aSUSPENDEDincident on the same account: don't suggest an appeal or close the suspension. Instagram can also restrict one feature of an account that keeps working ("You can't share links" until a date): the phone closes Instagram's restriction page and Pamba opens aFEATURE_RESTRICTEDincident whose detail carries the restriction and itsends_on. It never pauses posting or warming, shows through its end date and closes the day after.reconcile_tiktok_renamerepairs 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_ideasandget_idearead the library (twenty-five per page, sortable by date, views and engagement ratios); every hub video carries a replicationfeasibility_verdict(pass,fail,unjudged) with the judge's reason, andexclude_low_feasibility=truehides failed ones while unjudged stay visible.get_idealistsrequired_brand_assetswithin_libraryper 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) answerspayment_required.generate_script_from_ideaalso runs for a workspace holding credits it was given or bought, while any are left. 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_accountcannot remove an account linked to one of the workspace's avatars. - •
search_tracked_videossearches the workspace's own accounts by default (avatar-linked, signed in on its phones, or with a post it scheduled); passinclude_research_accounts=truefor the inspiration accounts. Ground recommendations there rather than in memory.generate_script_from_ideawrites a fresh script, thirty to forty-five seconds unless the idea asks for another length and in the idea's language, and does not save it;save_idea_scriptorcreate_video_projectdoes. - •Discover:
get_trending_videos(by default only avatar-replicable content, screened for promotion carriage;include_unproducible=truereveals everything),get_niche_feed(returnsniche_statuspendingorno_nichefor 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 aslive_searches_remaining_today),get_breakout_creators. To act:use_discover_videoputs a video on the Ideas board (idempotent),bookmark_discover_videosaves it,track_video_authoradds the creator as an inspiration account.browse_picker_videosis the create page's shelf; a row whosevideo_urlis null is an un-enriched Discover row, so prepare it withuse_discover_videofirst.
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_campaigncopies its schedule and starts disabled with no members;assign_avatar_to_campaignis a complete move.enable_campaignspends credits on every future cycle untildisable_campaign, and both need an active subscription on the workspace owner.run_campaign_nowplans the gap days up to the next scheduled cycle without stealing that cycle's window. - •
preview_content_planis a dry run that creates nothing;plan_content_batchplans (or re-plans an unapproved batch viabatch_id);get_content_planexplains, per avatar, why each got its slots;edit_plan_slotsmoves, removes, swaps, adds or pauses.approve_content_planorapprove_all_content_plansis where credit spend starts, and approval is refused while the plan has error-severity violations.set_mix_targetsreplaces all targets, so readget_content_strategyfirst.delete_planonly removes a planning or brief-pending batch and never touches projects. - •
push_content_batchis safe by default: withoutpush_now=trueor apreflight_idit only runs the preflight. Withpush_now, each pushed approved script becomes a fully automated project that generates and schedules, and spends video credits.decide_content_scriptwith abatch_idand noscript_idapproves every undecided script;require_green=trueskips scripts with failing checks.send_writer_chat_messageanswers asynchronously: read the thread withget_content_script(view=writer_chat), thenapply_script_revision. - •Knowledge base: patterns (a pattern's category is its canonical format;
lipsyncpatterns are classification-only, the planner never allocates them), principles, playbooks and term lists (tiered pools of real terms the writer draws from:proven,testingandexploratorytiers are writer-eligible,candidateandrisk_flaggedterms are not). The writer's references are chosen automatically at claim time from pattern links; curate them withmanage_pattern_linkand preview withget_pattern_references. - •
get_studio_overviewis the one read for the Drafts and Videos tabs. Always passstatuses:draftsis 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. Omittingstatusesreturns the classic queue capped at fifty with drafts sorted below everything else, which hides them on a busy workspace.sort(newest,oldest,posttime,views) decides which items make the window and requiresstatuses;viewsputs the items with the most views across their TikTok and Instagram posts first, with each item's count inviews, an item with no views yet carries noviews, and other sorts never send it (statuses=posted&sort=viewslists your top videos); a typo in either errors rather than defaulting.view=homealso returns the getting-live setup, whereready_to_post(notaccount_connected) says whether posting would actually work.
Analytics
- •
get_analytics_summary(daysone to three hundred sixty-five, default thirty;platformtiktok,instagramorfacebook, default TikTok; optionalavatar) gives views and followers per platform, broken down by up to twenty avatars. An inactive avatar's accounts stay in it as an archived account does, markedarchived: their old views keep counting and nothing new is read for them until the avatar is active again.search_tracked_videosis per-video TikTok performance,list_social_videosper-video Instagram and Facebook performance,get_tracked_account_metricsan account's lifetime totals and cadence. - •An Instagram slideshow or picture (
media_kindphoto) has no public view count: Instagram shows its views only to the account that posted it, so the account's Pamba phone reads them off the post's own insights, about three days after posting and a final time about four weeks after, andviews_read_atsays when. Every postlist_social_videos,search_tracked_videosandget_post_analyticsreturn carriesviews_source, where its views come from:public(the count the platform shows publicly, read by Pamba's hourly scrape: every TikTok and Facebook post, an Instagram reel, a slideshow posted as one included) orinsights(read off the post's insights by the account's phone: every other slideshow, and every picture). Aninsightspost with noviews_read_athas not been read yet: its views, 0 in a list and null onget_post_analytics, mean not known yet rather than zero views (the app shows a ? there). Its likes and comments come from the hourly read like a reel's. - •
get_post_analytics(platformtiktokorinstagram,video_idthe TikTok video id or the Instagram shortcode) is one post's page: its counts with their daily history and its audience (gender, age from 18 (no age under 18 is ever served), top locations, new vs returning viewers, followers vs not, watch time, finish rate, and its retention curve: the percent still watching at each second, with TikTok's average share watched and the moment most viewers stopped, or Instagram's skip rate) and its engagement (the likes, comments, shares, saves and Instagram's reposts as the app counts them; when in the video viewers liked it, at each second, on the app's own scale: TikTok's chart runs to 100% at its most liked moment, Instagram's gives each moment's share of the likes; TikTok's most liked moment and the words its comments use most; the like, comment, share, save and repost rates, Instagram's own, or for TikTok, which prints none, the read's counts over its views withrates_from_countstrue), andretention_moments, the percent still watching at 5 s, 10 s, halfway and the end with the skip rate, aslist_post_analyticsgives them, read by the account's phone off TikTok's Video analytics or Instagram's reel insights, with the screenshots behind each read. A post is first read once it has 200 views, at any age (or three days after posting with 100), and again as it passes 1,000, 5,000, 10,000 views and every doubling after, at most ten posts a day per account;next_readsays when.list_post_analytics(platformall,tiktokorinstagram,days1-365 (default 30),sortnewest,retention_5s,retention_end,skip_rate,like_rate,comment_rate,share_rateorsave_rate,limit1-100) lists the posts with a read, each read at a glance: the percent still watching at 5 s, 10 s, halfway and at the end (one second before it on a post up to 20 seconds long, the curve's second-to-last measured point on a longer one, since TikTok's chart falls to about zero in its last second), the skip rate (the app's own where it prints one, Instagram; otherwise the share gone in the first 3 seconds of the curve, withskip_rate_from_curvetrue), the share watched and the finish rate, and its engagement: the likes, comments, shares, saves and (Instagram) reposts the read counted, the share of viewers who did each (Instagram's own rates; TikTok prints none, so there each is the read's count over its views, withrates_from_countstrue) and TikTok's most liked moment. Each post also carries the listing's own likes, comments, shares and saves. These are the Retention and Engagement columns of All Videos. Each row'sretentionis left empty there (get_post_analyticshas the curve), andtotalsays how many matched.get_account_audienceis the account's own viewers (TikTok Studio, 28 days, read once the account has a post from the last 60 days) and followers breakdowns, read on its daily visit, with its latest daily health checks' screenshots; both apps show a followers breakdown only from 100 followers.get_audience_summary(segmentviewersorfollowers,platformall,tiktokorinstagram) is the workspace's audience across all its accounts on Pamba phones, each account counted by its size: viewers are TikTok Studio's (28 days) plus Instagram reels read in the last 28 days, followers are each app's followers breakdown; it lists the accounts folded in and when each was read, and is rebuilt as reads land. Each audience read and rollup these four tools return carriessample: how many people its numbers come from (viewers, or the views when the app printed no viewers, or followers on a followers read), the size from which such numbers are enough, and whether this read falls short of it, as most of a post's early reads and a small account's audience do. A read that falls short is low confidence: its shares, retention and rates can still move a lot as more people watch or follow, and the app marks an account's or the workspace's audience Low sample size (never a single post). A read with no count known carries nosample. These are the platforms' own estimates, as printed. - •The numbers are snapshots and the surfaces end their windows and total differently, so do not expect them to reconcile to the view. The summary tool and the app's dashboard read the same daily rows, each dated on its workspace's calendar; the summary ends its window on today in UTC, the dashboard on today in the viewer's timezone.
get_tracked_account_metricsdates its per-day series on the workspace's calendar too. The dashboard sums daily deltas, while per-account metrics sum lifetime view counts. A TikTok video's first snapshot carries everything it earned before Pamba first read it, and those counts land on the day the video was posted when Pamba first read it within 90 days of posting; a video it starts tracking later adds only its later growth. On every platform, the views a reading finds two or more days after a post's previous one (an account not read while its avatar was inactive, a scrape outage) are spread evenly over those days rather than landing on the day the reads resumed. Accounts assigned to a deactivated avatar keep posting and accruing views but do not appear in avatar-scoped dashboards. A TikTok rename keeps one account row: the hourly refresh follows the account through its stable id (or one of its own videos) and moves the row to the new handle, so both handles' videos stay together; a rename it cannot follow leaves the old row failing until it is reconciled by hand. 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_settingsis admins only; settingwebsite_urlre-scrapes the site and replaces the stored company profile (and the niche, unless it was hand-written).update_company_profileedits 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_workspacesreturns at most twenty workspaces andlist_workspace_membersone hundred. - •
create_workspacewithwebsite_urlsets 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); passniche_description,what_they_doandnameinstead when there is no site (withoutwhat_they_dothe brand stays unconfirmed and the result says how to finish it). Set up either way, the new workspace takes the goal of the workspace the call runs in (what it is for: accounts, videos or both). 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 theworkspace_id: finish or delete it, never create a second.delete_workspaceis 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. A signup wizard withstep_list_version2 first asks what the workspace is for (set_workspace_goal); foraccountsit runs only website, brand and the referral question beforecomplete_onboarding, and the accounts are bought after withpurchase_account_seats. Thelightflow of an added workspace ends afterset_onboarding_brandandcomplete_onboarding.set_onboarding_websiteis 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_optionsreturns an empty list while the niche match is still running, so poll again rather than treating it as no avatars.select_onboarding_presenterpicks a matched starter avatar for free;start_onboarding_avatargenerates one and spends image credits.create_onboarding_concept_projectsis free and idempotent. The device half must be resolved (purchased or skipped) beforecomplete_onboarding, which refuses otherwise, except on that accounts track, which needs only the brand.set_onboarding_referralaccepts only its listed sources, with free text indetailunderother. A user with no credits and no avatars right after signing up has a torn bootstrap;heal_signup_bootstrapre-runs the missing grants idempotently. - •
contact_supportposts into the user's private support conversation with the Pamba team (up to five thousand characters, plus up to four public image links inscreenshot_urls, PNG, JPEG or WebP, up to ten megabytes each); a user can send ten messages a minute and a hundred a day across every door, emails to support or to a team member included, and upload fifty screenshots a day. Acontact_emailstays on the conversation for later replies until another replaces it, and the result names the address replies go to. The team answers in the app's Support tab and by email, an unread answer rides every MCP tool result as asupport_replynotice (see How a call behaves), andget_support_messagesreads the conversation: who wrote each message, the text, screenshot links valid for an hour, andunread_count. Reading the newest page counts as the user seeing the replies, so the reply email is skipped. Over this transport no chat transcript is shared with the team, so put the context in the message.list_api_keys,create_api_keyandrevoke_api_keymanage keys; a revoked key's MCP connection fails at its next call.create_api_keyreturns 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. That includes the keycreate_api_keymakes withkey_workspace_idfor a workspace the connection's key created: it lands in the transcript too, so it suits a system integration rather than a person's own connection. - •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 workspace API key resolves to one user in one workspace, where workspace-bound tools run. It makes keys only there and in the workspaces it created itself (
create_api_keywithkey_workspace_id); a chat app's connection makes keys only in the workspace the call runs in. What acts on the person reaches past the key's workspace, as it does in the app:list_api_keysandrevoke_api_keycover their keys everywhere, anddelete_workspaceand the REST/workspaces/{workspaceId}/…routes (settings, members, invitations) act on any workspace they administer. An OAuth token resolves to one user and an explicit set of approved workspaces; each tool call resolves one approved workspace and verifies current membership before execution. Ownership checks are the same the app enforces: an id from another workspace answersnot_found, never data. Admins-only settings answerforbiddenfor 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. Revoking a key leaves the keys it made working, and the new key cannot make keys for the workspaces the old one created: keep a key made inside each of those, or make one later in that workspace's settings.
- •If a key leaks, revoke it, then clear what it made, since revoking removes none of it. Keys:
GET /api-keyslists every key you own with itsworkspace_idand when it was made and last used (list_api_keysshows the fifty newest and counts them all; a workspace's settings list only that workspace's keys). Revoke each one made since the leak, judging by date rather than name, since a key's name is whatever its maker typed, or revoke them all and make new ones. Members: a key can invite people into any workspace you administer, and an invitation link admits whoever accepts it, so check the members and pending invitations of each of those in its settings in the app, and remove what you did not add (over MCP,list_workspace_membersandlist_workspace_invitationsread only the workspace the connection runs in); check the key's own workspace's share links too (list_share_links). Workspaces:GET /workspaceslists every one you belong to with its owner (list_workspacesshows twenty and counts them all); delete any you own and do not recognize, and ask the admins of one you do not own to remove you. A leaked key could also have revoked your other keys or deleted a workspace you administer, never your default one.
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 answersstatus: busyat 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 versions2025-06-18and2025-11-25are accepted; anything else, including2025-03-26(whose transport requires batches), negotiates to2025-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/listif you mirror it. - •JSON-RPC errors:
-32700malformed JSON,-32600invalid request or batch,-32601unknown method,-32602unknown tool, tool outside the scope, bad arguments, unknown prompt or a missinguri,-32002resource not found (thedatanames the uri),-32603internal error. Auth failures are HTTP 401 before any message is read; a badtoolsets,readonlyormax_creditsvalue on the URL is HTTP 400 with a JSON-RPC error body.
