Overview
The API is REST over https with JSON in and out, at https://app.ninetytenlabs.com/api/v1. The same actions are available to AI assistants through an MCP server at https://app.ninetytenlabs.com/mcp, and webhooks tell your server when something happens. Everything a key does happens in its own workspace and nowhere else.
VideosUpload and edit
Resumable uploads up to 5 GB or import from a link, then a quick cut with face-aware captions, edit energy and list templates.
WritingScripts and captions
Scripts from an idea, carousels, and a caption written for each platform from what the video says.
PublishingPost and automate
Post now or schedule, per-post captions and sounds, comment-to-DM automations, and results per post.
Keys and scopes
Make a key in the app under Settings, Developer, and send it on every request: Authorization: Bearer ntl_live_.... A key is shown once, belongs to one workspace, and can be revoked at any time.
| Scope | What it allows | Who can give it |
read | Videos, clips, posts, results, credits, offers and guides. | Any seat. |
write | Uploads, imports, edits, scripts, carousels and captions. Paid jobs spend the workspace's credits. | Owners, managers and creators, on a paid plan. |
publish | Posting, scheduling and comment-to-DM automations. | Owners and managers. A creator's publish key asks for approval on each post instead. |
A key acts with the seat of the person who made it, never more than its scopes: if that person's seat changes, the key changes with it, and if they leave the workspace the key stops working. API and MCP access come with every paid plan. During a trial, keys read only.
Quick start
From a recording on your machine to posted on two channels. Webhooks save you from polling in step 4.
# 1. A slot for your recording (makes the video too)
curl -X POST https://app.ninetytenlabs.com/api/v1/uploads \
-H "Authorization: Bearer $NTL_KEY" -H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"title":"Pricing talk","contentType":"video/mp4","size":48211337}'
# 2. Send the file to upload.url, then confirm it arrived
curl -X PUT "$UPLOAD_URL" -H "Content-Type: video/mp4" --data-binary @talk.mp4
curl -X POST https://app.ninetytenlabs.com/api/v1/uploads/$UPLOAD_ID/complete -H "Authorization: Bearer $NTL_KEY" \
-H "Content-Type: application/json" -d '{}'
# 3. See the price, then start the edit at that price
curl https://app.ninetytenlabs.com/api/v1/productions/$VIDEO_ID/quote -H "Authorization: Bearer $NTL_KEY"
curl -X POST https://app.ninetytenlabs.com/api/v1/productions/$VIDEO_ID/edit \
-H "Authorization: Bearer $NTL_KEY" -H "Content-Type: application/json" \
-d '{"options":{"energy":"high"},"confirmCredits":120}'
# 4. When production.ready arrives (or status says ready): captions, then post
curl -X POST https://app.ninetytenlabs.com/api/v1/productions/$VIDEO_ID/captions \
-H "Authorization: Bearer $NTL_KEY" -H "Content-Type: application/json" \
-d '{"platforms":["instagram","tiktok"]}'
curl -X POST https://app.ninetytenlabs.com/api/v1/productions/$VIDEO_ID/posts \
-H "Authorization: Bearer $NTL_KEY" -H "Content-Type: application/json" \
-d '{"timing":"now","posts":[{"accountId":"$IG_ID","platform":"instagram"},{"accountId":"$TT_ID","platform":"tiktok"}]}'
Credits and retries
Paid calls say so in the reference. Each one works out its price first, holds the credits before any work starts, and gives them back if the work fails. The answer includes credits (what it cost) and balance. Send confirmCredits with the price you showed your user: if the price is different, nothing runs and the current price comes back with the code price_changed. Price anything first with GET /api/v1/credits/quote, or an edit with the video's quote.
Every POST accepts an Idempotency-Key header. Retry with the same key and the same body, and you get the first answer back (marked with Idempotent-Replayed: true) instead of the work, or the charge, happening twice. Successful answers are kept for 24 hours; a failed call can be retried with the same key.
Errors
Every error has the same shape, and never passes on another service's wording:
{
"error": {
"code": "insufficient_credits",
"message": "This needs 120 credits. Add credits and try again.",
"hint": "Add credits in Settings, Billing and credits, then try again."
}
}
| Status | Codes |
| 400 | invalid_request, url_not_allowed, url_not_video, url_unreachable |
| 401 | unauthorized |
| 402 | insufficient_credits |
| 403 | insufficient_scope, seat_not_allowed, plan_required |
| 404 | not_found, unknown_route |
| 409 | conflict, not_ready, price_changed, needs_context, idempotency_in_progress, not_connected, reconnect |
| 422 | idempotency_mismatch |
| 429 | rate_limited (wait for Retry-After seconds) |
| 503 | service_down, uploads_unavailable (nothing was lost or charged; try again) |
Endpoints
Also as an OpenAPI 3.1 document for code generators and API clients.
WorkspaceAccountsUploadsVideosWritingPublishingAutomationsResultsCreditsContent
Workspace
GET/api/v1/me
The key and its workspace. The workspace this key belongs to, its scopes, the seat it acts with, whether the plan allows writing, and the rate limit.
scope: read
Returns workspace, key, seat, publishing, plan, rateLimit.
Accounts
GET/api/v1/accounts
Connected accounts. The social accounts connected to this workspace. Use an account id when posting.
scope: read
Returns accounts.
Uploads
POST/api/v1/uploads
Get an upload slot. A signed slot for one recording (MP4, MOV or WebM up to 5 GB). Send the file with one PUT to upload.url, or resumably (tus) to resumable.endpoint with the headers given. Then call complete. Makes a new video when productionId is left out.
scope: write
Parameters and body
| Field | Type | What it is |
|---|
productionId | string (uuid) | An existing video waiting for footage. Left out, a new video is made. |
title | stringup to 120 characters | |
template | "talking_head" | "list" | "tier_ranking" | "challenge" | "broll" | |
contentType required | "video/mp4" | "video/quicktime" | "video/webm" | "video/x-m4v" | |
size required | integerat most 5368709120 | Exact size in bytes. |
Returns uploadId, productionId, expiresInSeconds, upload, resumable.
POST/api/v1/uploads/{id}/complete
Confirm an upload arrived. Checks the file arrived whole at the size promised and attaches it to its video. Nothing is edited or charged yet; start the edit next.
scope: write
Parameters and body
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
Returns production.
Videos
GET/api/v1/productions
Videos. This workspace's videos, newest first.
scope: read
Parameters
| Field | Type | What it is |
|---|
limit query | integer1 to 100 | |
Returns productions.
POST/api/v1/productions
Make a video, or import one from a link. Makes a video waiting for footage, or, with sourceUrl, imports a recording from a public https link (checked before it is accepted). Choices for the edit are saved; nothing is charged until the edit starts.
scope: write
Parameters and body
| Field | Type | What it is |
|---|
title required | stringup to 120 characters | |
template | "talking_head" | "list" | "tier_ranking" | "challenge" | "broll"default "talking_head" | list and tier_ranking add a ranked board with logos. |
brief | stringup to 4000 characters | What the video is about, for the editor. |
sourceUrl | string (uri)up to 2048 characters | A public https link to a video file. |
timezone | stringup to 80 characters | |
options | object | |
options.engine | "auto" | "fast_cut" | "deep" | auto picks the quick cut for recordings up to 10 minutes and the full edit for longer ones. |
options.energy | "calm" | "standard" | "high" | "jumpcut" | "static" | How much the picture moves, every move eased. calm (Calm): a slow push only. standard (Smooth, the default): always gently moving, a soft punch-in on key lines. high (Lively): stronger punch-ins on more beats. jumpcut: the framing steps at each cut with a slow creep between. static: no motion. |
options.layout | "auto" | "fill" | "fit" | For horizontal footage: fill crops to vertical, fit keeps the whole frame with text above and below. auto: fit for horizontal, fill for vertical. |
options.broll | object | B-roll cutaways. Off unless asked for; adds to the price. |
options.broll.images | boolean | |
options.broll.video | boolean | |
options.loop | boolean | A Loop: about 8 seconds of the footage that plays on repeat, one big line of text on screen and a sound under it, for footage with no talking. Left out, a recording with no talking, or a brief that asks for a POV, b-roll or text over footage, becomes one on its own. |
Returns production.
GET/api/v1/productions/{id}
Video status and progress. Where a video is: its status, the edit stage, clips rendered, and any message.
scope: read
Parameters
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
Returns production, progress.
GET/api/v1/productions/{id}/quote
Price an edit. What editing this recording will cost, read from the file itself, and which editor it gets.
scope: read
Parameters
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
Returns engine, job, credits, balance, seconds.
POST/api/v1/productions/{id}/edit
Start the edit. Starts editing an uploaded or imported recording into short clips. Priced from the recording; the credits are held when it starts and released if it fails.
scope: writepaid
Parameters and body
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
options | object | |
options.engine | "auto" | "fast_cut" | "deep" | auto picks the quick cut for recordings up to 10 minutes and the full edit for longer ones. |
options.energy | "calm" | "standard" | "high" | "jumpcut" | "static" | How much the picture moves, every move eased. calm (Calm): a slow push only. standard (Smooth, the default): always gently moving, a soft punch-in on key lines. high (Lively): stronger punch-ins on more beats. jumpcut: the framing steps at each cut with a slow creep between. static: no motion. |
options.layout | "auto" | "fill" | "fit" | For horizontal footage: fill crops to vertical, fit keeps the whole frame with text above and below. auto: fit for horizontal, fill for vertical. |
options.broll | object | B-roll cutaways. Off unless asked for; adds to the price. |
options.broll.images | boolean | |
options.broll.video | boolean | |
options.loop | boolean | A Loop: about 8 seconds of the footage that plays on repeat, one big line of text on screen and a sound under it, for footage with no talking. Left out, a recording with no talking, or a brief that asks for a POV, b-roll or text over footage, becomes one on its own. |
confirmCredits | integer | The price you agreed to, in credits. When sent it must equal the current quote, or nothing runs and the new price comes back. |
Returns production, credits, balance.
POST/api/v1/productions/{id}/edit/accept
Accept a new edit price. An edit never costs more than the price confirmed. When the recording turns out dearer (longer than it looked, a length that could not be read, or it needs the longer edit), nothing is charged and the video waits with choice set. This starts it at the new price; if it now costs less, the lower price is charged.
scope: writepaid
Parameters and body
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
confirmCredits required | integer | Must equal choice.credits, or nothing runs and the current price comes back. |
Returns production, credits, balance.
POST/api/v1/productions/{id}/edit/keep
Keep a video as it is. Answers a waiting price choice with no. Nothing starts and nothing is charged; the recording stays on the video.
scope: write
Parameters and body
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
Returns production.
GET/api/v1/productions/{id}/clips
Clips and versions. The finished clips of a video. Post one by its id.
scope: read
Parameters
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
Returns clips.
POST/api/v1/productions/{id}/clips/{key}/look
Change a clip's look. Changes one quick-cut clip (layout, headline, energy, caption position) and renders just that clip again.
scope: writepaid
Parameters and body
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
key path required | string | |
framing | "fill" | "fit" | |
band | "solid" | "blur" | |
headline | stringup to 80 characters | |
subline | stringup to 90 characters | |
bottom | "captions" | "subline" | |
energy | "calm" | "standard" | "high" | "jumpcut" | "static" | |
captionY | number or null | |
confirmCredits | integer | The price you agreed to, in credits. When sent it must equal the current quote, or nothing runs and the new price comes back. |
Returns clip, credits, balance.
Writing
POST/api/v1/writing/script
Write a script from an idea. A recordable script (three hooks, body, call to action) written from an idea and this workspace's brand brain.
scope: writepaid
Parameters and body
| Field | Type | What it is |
|---|
idea required | stringup to 6000 characters | |
audience | stringup to 1000 characters | |
offer | stringup to 1000 characters | |
template | "talking_head" | "list" | "tier_ranking" | "challenge" | "broll"default "talking_head" | |
purpose | "reach" | "connection" | "trust" | "conversion"default "reach" | |
research | boolean | Look up current facts first. |
confirmCredits | integer | The price you agreed to, in credits. When sent it must equal the current quote, or nothing runs and the new price comes back. |
Returns script, credits, balance.
POST/api/v1/writing/carousel
Write a carousel. A carousel (title, caption, 2 to 10 slides) written from an idea and this workspace's brand brain.
scope: writepaid
Parameters and body
| Field | Type | What it is |
|---|
idea required | stringup to 6000 characters | |
audience | stringup to 1000 characters | |
offer | stringup to 1000 characters | |
purpose | "reach" | "connection" | "trust" | "conversion"default "reach" | |
confirmCredits | integer | The price you agreed to, in credits. When sent it must equal the current quote, or nothing runs and the new price comes back. |
Returns carousel, credits, balance.
POST/api/v1/productions/{id}/captions
Write captions per platform. One caption per platform (and a YouTube title), written from what the video says. The first write for a video is free; rewrites are charged once per call.
scope: writepaid
Parameters and body
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
platforms required | array of "instagram" | "facebook" | "tiktok" | "youtube" | "linkedin" | "twitter" | "threads" | "bluesky" | "pinterest" | "reddit" | "googlebusiness" | "snapchat" | "telegram" | "whatsapp" | "discord" | "slack"up to 8 items | |
version | stringup to 200 characters | |
confirmCredits | integer | The price you agreed to, in credits. When sent it must equal the current quote, or nothing runs and the new price comes back. |
Returns captions, credits, balance.
Publishing
POST/api/v1/productions/{id}/posts
Post now or schedule. Posts a finished video to chosen accounts, now or at set times, each post with its own caption and sound. A caption left out uses the one saved for that platform. Posting is free on every platform. A key made by a creator seat asks for approval instead of posting.
scope: publishcreator seat: asks for approval
Parameters and body
| Field | Type | What it is |
|---|
id path required | string (uuid) | |
timing required | "now" | "scheduled" | |
timezone | stringup to 80 characters | |
posts required | array of objectsup to 20 items | |
posts[].accountId required | stringup to 100 characters | |
posts[].platform required | "instagram" | "facebook" | "tiktok" | "youtube" | "linkedin" | "twitter" | "threads" | "bluesky" | "pinterest" | "reddit" | "googlebusiness" | "snapchat" | "telegram" | "whatsapp" | "discord" | "slack" | |
posts[].version | stringup to 200 characters | A clip id from list clips. Left out: the chosen cut, else the first clip. |
posts[].at | string (date-time) | When to post (scheduled only). |
posts[].caption | stringup to 2200 characters | |
posts[].title | stringup to 100 characters | YouTube title. |
posts[].delivery | "public" | "trial" | "trial_auto" | Instagram: public feed, trial reel, or trial that goes public if it performs. |
posts[].sound | object | A sound for this post only. |
again | boolean | Post again to an account this video is already posted or scheduled on. Left out: those posts are refused, so nothing goes out twice by accident. |
confirmCredits | integer | The price you agreed to, in credits. When sent it must equal the current quote, or nothing runs and the new price comes back. |
Returns posts, approval, credits, balance.
GET/api/v1/posts
Posts. Scheduled and published posts, newest first.
scope: read
Parameters
| Field | Type | What it is |
|---|
limit query | integer1 to 100 | |
Returns posts.
Automations
GET/api/v1/automations
Comment-to-DM automations. Automations on this workspace's Instagram and Facebook accounts, with their counts.
scope: read
Returns automations.
POST/api/v1/automations
Make a comment-to-DM automation. When someone comments a keyword (or replies to a story), they get a DM with up to three link buttons, plus an optional public reply. Needs a manager or owner seat.
scope: publish
Parameters and body
| Field | Type | What it is |
|---|
name required | stringup to 80 characters | |
accountId required | stringup to 80 characters | |
trigger | "comment" | "story_reply" | |
platformPostId | stringup to 120 characters | One post only. Left out: every post. |
keywords | array of stringup to 20 items | |
matchMode | "contains" | "word" | "exact" | |
alsoMatchInDms | boolean | |
dmMessage required | stringup to 640 characters | |
buttons | array of objectsup to 3 items | |
buttons[].title required | stringup to 20 characters | |
buttons[].url required | string (uri)up to 2000 characters | |
commentReplies | array of stringup to 5 items | |
dmDelaySeconds | integer0 to 3600 | |
Returns automation.
PATCH/api/v1/automations/{id}
Arm or pause an automation. Turns an automation on (armed) or off. Needs a manager or owner seat.
scope: publish
Parameters and body
| Field | Type | What it is |
|---|
id path required | string | |
active required | boolean | |
Returns automation.
Results
GET/api/v1/analytics
Post and account results. Views, likes, comments, shares and saves for recent posts on this workspace's accounts. A number the platform did not report is null, never zero.
scope: read
Returns retrievedAt, totalPosts, posts.
Credits
GET/api/v1/credits
Balance and prices. The credit balance this workspace spends from, its monthly budget, the price of every job (a credit is a cent), and when the credits in the balance expire, soonest first. Plan credits expire at the next monthly grant, top-ups and bonuses 90 days after they land, free credits after 30 days without activity; the soonest to expire are spent first.
scope: read
Returns balance, monthlyBudget, prices, lots.
GET/api/v1/credits/quote
Price a job. What one job costs before you run it. For an edit of a recording you already uploaded, use the video's quote instead. A month plan is priced by its pieces (pieces, 30 when left out); a caption restyle and a graphics plan by the finished video's length past 10 minutes (sourceMinutes).
scope: read
Parameters
| Field | Type | What it is |
|---|
job query required | "written_post" | "video_script" | "carousel" | "clip" | "fast_cut" | "fast_cut_rerender" | "long_form" | "review_reply" | "month_plan" | "decode" | "ugc" | "ugc_frame" | "graphics" | "graphics_plan" | "caption_restyle" | |
sourceMinutes query | number0 to 600 | The recording's length for a deep edit, or the finished video's for a caption restyle or a graphics plan. |
pieces query | integer1 to 60 | A month plan: the pieces in the month (videos, Loops, carousels and posts). |
Returns job, credits, balance.
Content
GET/api/v1/offers
Offers. The confirmed offers written in Brand brain.
scope: read
Returns offers.
GET/api/v1/guides
Guides. Published guides and their public links.
scope: read
Returns guides.
Webhooks
Add an https endpoint in Settings, Developer, pick the events it should hear, and keep the signing secret shown when you add it. Each event is a POST with a JSON body. Answer with any 2xx within 10 seconds. Anything else is retried after 1 min, 5 min, 15 min, 1 h, 3 h, 6 h, 12 h: 8 tries in all, about a day. The same event keeps its id across retries, so you can drop repeats. The Send test event button sends a sample marked "test": true.
| Event | When |
|---|
production.ready | An edit finished and its clips are ready to review and post. |
production.failed | An edit stopped and needs attention. Any held credits were released. |
post.published | A post went live on its platform. |
post.failed | A post could not go out, or its outcome needs checking. |
automation.dm_sent | A comment-to-DM automation sent new DMs since the last check (checked every few minutes). |
credits.low | The balance dropped below the threshold set on the endpoint. |
lead.captured | Someone started one of your DM flows: their name, handle, the flow and any answers so far. |
lead.updated | A lead tapped an answer in a DM flow, or you moved them to a new stage. |
{
"id": "8f0c2d1e-5a3b-4c7d-9e11-2b6f4a1c0d33",
"type": "production.ready",
"created": "2026-09-26T15:04:05.000Z",
"workspace": "ws_7Qm2",
"data": {
"productionId": "3a1f9b2c-7d4e-4f60-8a15-c2e9d0b41f77",
"title": "Pricing talk",
"state": "review_ready",
"publicationState": "draft"
}
}
Every delivery carries x-ntl-event, x-ntl-delivery, x-ntl-timestamp and x-ntl-signature. The signature is an HMAC-SHA256 of timestamp.body with your endpoint's secret. Check it, and refuse timestamps more than five minutes old:
import crypto from "node:crypto";
// Express: app.post("/hooks", express.raw({ type: "application/json" }), handler)
function verified(req, secret) {
const header = req.get("x-ntl-signature") || ""; // t=1790000000,v1=5f2c...
const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
const body = req.body.toString("utf8");
const expected = crypto.createHmac("sha256", secret).update(parts.t + "." + body).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return fresh && parts.v1?.length === 64 &&
crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(parts.v1, "hex"));
}
Endpoints must be https addresses on the public internet. The address is checked when you save it and again on every delivery.
AI assistants (MCP)
The MCP server at https://app.ninetytenlabs.com/mcp gives an AI assistant the same actions as the API, with the same key, scopes and seat. It only lists the tools a key's scopes allow. Paid tools answer first with their price; the assistant tells you, and runs the tool only when it calls again with confirm_credits equal to that price.
Claude Code
claude mcp add --transport http ninetytenlabs https://app.ninetytenlabs.com/mcp \
--header "Authorization: Bearer ntl_live_YOUR_KEY"
Cursor (~/.cursor/mcp.json)
{
"mcpServers": {
"ninetytenlabs": {
"url": "https://app.ninetytenlabs.com/mcp",
"headers": {
"Authorization": "Bearer ntl_live_YOUR_KEY"
}
}
}
}
Claude Desktop (claude_desktop_config.json, needs Node.js)
{
"mcpServers": {
"ninetytenlabs": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://app.ninetytenlabs.com/mcp",
"--header",
"Authorization:${NTL_AUTH}"
],
"env": {
"NTL_AUTH": "Bearer ntl_live_YOUR_KEY"
}
}
}
}
Other assistants that can send a header work the same way: Streamable HTTP, POST https://app.ninetytenlabs.com/mcp, Authorization: Bearer with your key.
| Tool | What it does | Scope |
|---|
list_accounts | The social accounts connected to this workspace. Account ids are needed to post. | read |
get_upload_slot | A signed slot to upload one recording (MP4, MOV or WebM up to 5 GB). Upload the file with one PUT to upload.url, then call complete_upload. Makes a new video unless video_id is given. | write |
complete_upload | After the file is uploaded: checks it arrived whole and attaches it to its video. Nothing is charged; create_video starts the edit. | write |
import_from_url | Makes a video from a public https link to a video file (checked first). Nothing is charged; create_video starts the edit. | write |
create_video | Edits an uploaded or imported recording into captioned short clips (quick cut for recordings up to 10 minutes). Paid: call without confirm_credits to get the price, tell the person, and call again with confirm_credits only after they agree. | write |
accept_edit_price | When get_video_status shows a choice (the edit would cost more than the price agreed), nothing was charged. Tell the person the new price and the reason, and call this with confirm_credits equal to choice.credits only after they agree. | write |
keep_video_as_is | Answers a waiting price choice with no: nothing starts and nothing is charged. | write |
get_video_status | Where a video is: status (waiting_for_footage, editing, ready, failed, posted...), the edit stage, clips rendered, and any price choice waiting for the person. | read |
list_videos | This workspace's videos, newest first. | read |
list_clips | The finished clips of a video, with preview links. Post a clip by its id. | read |
restyle_clip | Changes one quick-cut clip (layout, headline, energy) and renders it again. Paid: price first, confirm_credits after the person agrees. | write |
write_script | A recordable script (three hooks, body, call to action) from an idea, in this workspace's voice. Paid: price first, confirm_credits after the person agrees. | write |
make_carousel | A carousel (title, caption, 2 to 10 slides) from an idea. Paid: price first, confirm_credits after the person agrees. | write |
write_captions | One caption per platform (and a YouTube title) written from what the video says, saved for posting. The first write for a video is free; rewrites are paid (price first). | write |
schedule_post | Schedules a finished video to chosen accounts, each post at its own time with its own caption and sound. Posting is free on every platform. From a creator seat this asks a manager for approval instead. | publish |
post_now | Posts a finished video now to chosen accounts, each with its own caption and sound. Always confirm with the person before posting. Posting is free on every platform. From a creator seat this asks a manager for approval instead. | publish |
list_posts | Scheduled and published posts, newest first. | read |
list_comment_to_dm | Automations on this workspace's Instagram and Facebook accounts, with how many DMs each sent. | read |
create_comment_to_dm | When someone comments a keyword, they get a DM with up to three link buttons. Needs a manager or owner seat. Confirm the wording with the person first. | publish |
set_comment_to_dm | Turns an automation on or off. Needs a manager or owner seat. | publish |
get_analytics | Views, likes, comments, shares and saves for recent posts. A number the platform did not report is null. | read |
get_credits | The credit balance, monthly budget and the price of every job. | read |
quote | What a job costs before running it. With video_id, what editing that recording costs (read from the file). | read |
Limits
| Requests | 120 a minute per key, API and MCP together. Headers show what is left: X-RateLimit-Remaining, X-RateLimit-Reset. |
| Keys | 10 active keys per workspace. |
| Uploads | MP4, MOV or WebM up to 5 GB. An upload slot is good for two hours. |
| Request bodies | Up to 64 KB of JSON. |
| Idempotency keys | 1 to 255 characters, answers kept for 24 hours. |
| Webhooks | 10 endpoints per workspace, 8 delivery tries per event. |