EditCaption

Technical documentation

EditCaption API documentation

Complete reference for the REST API and the MCP server: authentication, endpoints, job statuses, errors, code examples and agency workspace control. For pricing and creating a key, see the API page.

Overview

The EditCaption API always follows the same 3 steps: upload a media file, start a job (one endpoint per tool), then poll the job until it's done and download the result. Costly tools (captions, transcription, audio, voices) use your workspace's credits, at the same rate as in the app, reserved at launch and fully refunded if the job fails; the others are free. The REST API is included in the Pro and Scale plans; the MCP server is included in every plan, and it also runs your agency workspace (brands, posts, scheduling, analytics).

# 1. Upload a video (file or public URL)
curl -X POST https://editcaption.com/api/v1/uploads \
  -H "Authorization: Bearer ecap_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/my-video.mp4"}'
# → { "uploadId": "…", "durationSeconds": 53, "expiresIn": 10800 }

# 2. Start a job (here: automatic captions)
curl -X POST https://editcaption.com/api/v1/subtitles \
  -H "Authorization: Bearer ecap_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"uploadId": "…"}'
# → { "jobId": "…", "status": "queued", "creditsUsed": 18,
#     "creditsRemaining": 9982, "estimatedSeconds": 80 }

# 3. Poll the job until "completed", then download
curl https://editcaption.com/api/v1/jobs/JOB_ID \
  -H "Authorization: Bearer ecap_live_YOUR_KEY"
# → { "status": "completed", "result": { "url": "/api/download/…", "filename": "…" } }

Authentication

All /api/v1/* routes and the MCP server use the same API key, sent as a standard HTTP header:

Authorization: Bearer ecap_live_...
Key formatecap_live_…
CreationFrom My account → Developer (the full key is only shown once, when it's created), or automatically when you authorize an MCP connector (Claude, ChatGPT, Perplexity, see MCP server), in which case it's never shown in clear and can only be used by that connector.
Server-side storageOnly a fingerprint (sha256) is stored: the key can never be retrieved in clear after it's created.
RevocationFrom the dashboard, anytime. A revoked key immediately gets 401 on every endpoint (and the MCP server).
PlansAccess depends on the door, not the key: /api/v1 is reserved for the Pro and Scale plans (otherwise 403 plan_required); the MCP server is open to every plan, the free Solo plan included. The same key works for both and uses the workspace's credits.

Credits & plans

One rule for the app, the MCP and the API: each tool has a fixed credit cost (grid below and in each endpoint), taken from the workspace's wallet (owner), shared by the team. The plan's monthly credits go first (reset every month, no rollover), then topped-up credits (no expiry). A failed job is refunded in full, each pot getting its share back.

Solo300 credits a month (after email verification) · REST API not included · MCP included · 20 requests/min
Starter4,000 credits a month · REST API not included · MCP included · 60 requests/min
Pro9,000 credits a month · REST API included · MCP included · 120 requests/min
Scale20,000 credits a month · REST API included · MCP included · 240 requests/min

Top-ups (paid plans) from Settings → Workspace: 3,000 credits for €9, 7,000 credits for €19, 15,000 credits for €39. Balance anytime: GET /api/v1/account or the MCP whoami tool.

Limits & file formats

Max file size5 GB, for direct upload as well as URL ingestion.
Max lengthNo specific length limit: only the 5 GB size limit applies.
Input video formatsAny common video format (mp4, mov, avi, mkv, webm…). Formats aren't checked at upload: an error only shows up during processing if the file is unreadable.
Output video formatsmp4, webm, mov, avi, mkv (convert); mp4 (captions, watermark, trim, voice change, merge).
Output audio formatsmp3, wav, aac (extraction); wav (text to speech).
File retention3 hours after upload or job completion. A result can be downloaded several times during that window (unlike the public website, where the file is deleted after the first download).
Rate limitPer account and per minute, API and MCP combined: Solo 20, Starter 60, Pro 120, Scale 240. Above that: 429 rate_limited with a Retry-After header. Polling every 3 seconds stays under the Pro limit.

Job statuses & polling

Each job goes through 4 possible statuses, returned by GET /api/v1/jobs/:id:

queuedThe job is queued, not yet picked up by a worker.
processingThe job is running.
completedFinished successfully. The response contains result.url and result.filename.
failedFailed. The response contains an error field (message). Reserved credits are refunded in full automatically.

No webhooks: poll

The API doesn't send an HTTP callback when a job completes: poll GET /api/v1/jobs/:id periodically. Every launch response (status: "queued") includes an indicative estimatedSeconds: a good basis for your first wait. In practice, poll every 2 to 5 seconds, no aggressive backoff needed (no rate limit for now), until completed or failed.

Error handling

Every error returns a JSON body shaped like { error: { code, message } } with the matching HTTP status. Possible codes, across all endpoints:

StatuscodeWhen
400invalid_requestMissing or invalid parameter (detailed per endpoint below).
401unauthorizedAuthorization header missing, invalid or revoked key.
402insufficient_creditsInsufficient balance. The response adds balance, required, upgradeUrl and, on a paid plan, topupUrl.
403plan_requiredPlan without REST API access (Pro and Scale only), or account without a workspace. The response adds upgradeUrl.
403email_not_verifiedSolo plan with an unverified email address (its free credits are locked). The response adds verifyUrl.
429rate_limitedToo many requests per minute for your plan. See the Retry-After header.
404not_foundJob not found, expired, or owned by another API key.
500internal_errorUnexpected server error. Try again; contact us if it persists.
{
  "error": {
    "code": "insufficient_credits",
    "message": "You have 12 credits left and this action needs 60. Top up here: https://editcaption.com/espace/reglages#credits, or switch to a bigger plan: https://editcaption.com/prix",
    "balance": 12,
    "required": 60,
    "topupUrl": "https://editcaption.com/espace/reglages#credits",
    "upgradeUrl": "https://editcaption.com/prix"
  }
}

Reference

Endpoints

All routes below accept a JSON body (Content-Type: application/json), except /api/v1/uploads which also accepts multipart.

POST/api/v1/uploads

Upload media

Ingests a video or audio file, either by direct multipart upload ("file" field) or as JSON with a public URL to download. Returns an uploadId that all other endpoints can use for 3 hours. Always the first step before calling a tool.

Parameters

ParameterTypeDefaultDescription
filestring—Binary file (multipart/form-data). Mutually exclusive with url.
urlstring—Public http(s) URL of the media to download (JSON). Mutually exclusive with file.

Example request

curl -X POST https://editcaption.com/api/v1/uploads \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://exemple.com/ma-video.mp4"}'

200 response

{
  "uploadId": "3f2a9c7e-...",
  "durationSeconds": 53,
  "expiresIn": 10800
}

Possible errors

400
invalid_request
Neither file nor url given, invalid/unreachable URL, or file over 5 GB.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
  • ·Max size: 5 GB, both for direct upload and URL (the limit is enforced during the download, not just on the Content-Length header).
  • ·The media length is measured right away (ffprobe) and returned in the response: it's the basis for the cost of the tools that follow.
POST/api/v1/subtitles20 credits / min

Burned-in automatic captions

Transcribes the audio and burns styled captions right into the video (rendered, not a separate .srt file; see /api/v1/transcribe for that).

Parameters

ParameterTypeDefaultDescription
uploadIdrequiredstring—Returned by POST /api/v1/uploads.
stylestringclassiqueclassique = drop shadow, impact = rectangular background, contour = thick colored outline.
Values: classique | impact | contour
colorstring#FFFFFFText color, hex #RRGGBB.
effectColorstring#000000Color of the shadow (classique), background (impact) or outline (contour).
positionnumber820 = top of the screen, 100 = bottom. Note: inverted compared to the slider on editcaption.com.
sizestringnormaleText size.
Values: petite | normale | grande
captionWordsinteger4Words per caption group shown (ignored if srtContent is given with a fixed split).
Values: 1 | 2 | 4
srtContentstring—Your own .srt content (skips automatic transcription), handy to reuse a transcription you already corrected.
fontIdstringinterDisplay font.
Values: inter | montserrat | poppins | fredoka | archivo-black | anton
karaokeModestringnoneKaraoke-style word-by-word highlight. Ignored if captionWords = 1.
Values: none | couleur | taille | halo
highlightColorstring#FFD166Color of the active word in karaoke mode.
shadowIntensitynumber600-100. classique style only.
contourThicknessnumber500-100. contour style only.
boxOpacitynumber750-100. impact style only.

Example request

curl -X POST https://editcaption.com/api/v1/subtitles \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"uploadId":"3f2a9c7e-...","style":"impact","color":"#FFFFFF","position":85,"captionWords":2}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 18,
  "creditsRemaining": 9982,
  "estimatedSeconds": 80
}

Possible errors

400
invalid_request
uploadId missing, captionWords not in {1,2,4}, or srtContent doesn't contain "-->".
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
POST/api/v1/transcribe15 credits / min

Transcription (text or SRT)

Transcribes a video's audio into a downloadable plain-text file or .srt captions, without burning them into the video.

Parameters

ParameterTypeDefaultDescription
uploadIdrequiredstring—Returned by POST /api/v1/uploads.
languagestringautoISO 639-1 code (fr, en, es…) or "auto" for automatic detection. See the languages appendix.
formatstringtxttxt = continuous text with line breaks at sentence ends. srt = timestamped captions.
Values: txt | srt
srtSplitModestringphraseOnly with format=srt. "phrase" groups words into full sentences, one per entry. "mot" gives one entry per word, each with its own start and end timecode. Both keep the text as is (punctuation and case): for styled, burned-in captions, see /api/v1/subtitles.
Values: "phrase" | "mot"

Example request

curl -X POST https://editcaption.com/api/v1/transcribe \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"uploadId":"3f2a9c7e-...","format":"srt","srtSplitMode":"mot"}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 14,
  "creditsRemaining": 9968,
  "estimatedSeconds": 16
}

Possible errors

400
invalid_request
uploadId missing, invalid format, or invalid srtSplitMode.
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
POST/api/v1/clean-audio10 credits / min

Audio clean-up

Removes background noise and clarifies the voice in a video. No settings: fully automatic.

Parameters

ParameterTypeDefaultDescription
uploadIdrequiredstring—Returned by POST /api/v1/uploads.

Example request

curl -X POST https://editcaption.com/api/v1/clean-audio \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"uploadId":"3f2a9c7e-..."}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 9,
  "creditsRemaining": 9959,
  "estimatedSeconds": 80
}

Possible errors

400
invalid_request
uploadId missing.
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
POST/api/v1/extract-audioFree

Audio extraction

Extracts a video's audio track in the requested format.

Parameters

ParameterTypeDefaultDescription
uploadIdrequiredstring—Returned by POST /api/v1/uploads.
formatstringmp3Output audio file format.
Values: mp3 | wav | aac

Example request

curl -X POST https://editcaption.com/api/v1/extract-audio \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"uploadId":"3f2a9c7e-...","format":"wav"}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 3,
  "creditsRemaining": 9956,
  "estimatedSeconds": 16
}

Possible errors

400
invalid_request
uploadId missing or unsupported format.
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
POST/api/v1/convertFree

Format conversion

Converts a video to another container format.

Parameters

ParameterTypeDefaultDescription
uploadIdrequiredstring—Returned by POST /api/v1/uploads.
formatstringmp4Output video format.
Values: mp4 | webm | mov | avi | mkv

Example request

curl -X POST https://editcaption.com/api/v1/convert \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"uploadId":"3f2a9c7e-...","format":"webm"}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 5,
  "creditsRemaining": 9951,
  "estimatedSeconds": 80
}

Possible errors

400
invalid_request
uploadId missing or unsupported format.
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
POST/api/v1/mergeFree

Merge videos

Merges at least 2 uploaded videos into one, joined in the order of the given array.

Parameters

ParameterTypeDefaultDescription
uploadIdsrequiredarray—At least 2 uploadIds, in the order you want them merged.

Example request

curl -X POST https://editcaption.com/api/v1/merge \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"uploadIds":["3f2a9c7e-...","a11b22cc-..."]}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 10,
  "creditsRemaining": 9941,
  "estimatedSeconds": 160
}

Possible errors

400
invalid_request
uploadIds missing, fewer than 2 items, or an item isn't a valid uploadId.
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
  • ·The result is a new, independent file: the source uploadIds stay valid (and downloadable separately) until they expire after 3h.
POST/api/v1/watermarkFree

Image or text watermark

Adds a watermark as a repeated tiled pattern ("fixe") or a floating position that moves every 3/5/8 seconds ("flottant"). The watermark can be an uploaded image or text (rendered as a logo automatically).

Parameters

ParameterTypeDefaultDescription
uploadIdrequiredstring—Video to watermark, returned by POST /api/v1/uploads.
watermarkUploadIdstring—uploadId of an image (uploaded first via /api/v1/uploads). Required if watermarkText is missing.
watermarkTextstring—Text to turn into a logo. Required if watermarkUploadId is missing.
typestringfixefixe = tilted pattern repeated across the frame. flottant = a single instance that moves around.
Values: fixe | flottant
opacityinteger80Watermark opacity.
Values: 10-100
intervalinteger5Seconds between two positions. Floating mode only.
Values: 3 | 5 | 8

Example request

curl -X POST https://editcaption.com/api/v1/watermark \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"uploadId":"3f2a9c7e-...","watermarkText":"@moncompte","type":"flottant","opacity":70}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 5,
  "creditsRemaining": 9936,
  "estimatedSeconds": 80
}

Possible errors

400
invalid_request
uploadId missing, neither watermarkUploadId nor watermarkText given, or invalid type.
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
POST/api/v1/trimFree

Trim a segment

Keeps the [start, end] segment of a video, in seconds.

Parameters

ParameterTypeDefaultDescription
uploadIdrequiredstring—Returned by POST /api/v1/uploads.
startrequirednumber—Segment start in seconds, ≥ 0.
endrequirednumber—Segment end in seconds, must be > start.

Example request

curl -X POST https://editcaption.com/api/v1/trim \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"uploadId":"3f2a9c7e-...","start":12.5,"end":45}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 2,
  "creditsRemaining": 9934,
  "estimatedSeconds": 48
}

Possible errors

400
invalid_request
uploadId missing, start < 0, or end ≤ start.
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
  • ·The source video isn't used up by this call: it stays available for other segments until it expires after 3h.
POST/api/v1/text-to-speech15 credits / 1,000 chars (40 with a cloned voice)

Text to speech

Generates an audio file (.wav) from text, with a catalog voice or the account's cloned voice.

Parameters

ParameterTypeDefaultDescription
textrequiredstring—Text to synthesize.
voicestringlea"clone" uses the cloned voice saved on the account that owns the key; error 400 if no voice was saved on editcaption.com.
Values: id from GET /api/v1/voices | clone

Example request

curl -X POST https://editcaption.com/api/v1/text-to-speech \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"text":"Bienvenue dans cette vidéo générée automatiquement.","voice":"thomas"}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 1,
  "creditsRemaining": 9933,
  "estimatedSeconds": 10
}

Possible errors

400
invalid_request
text missing, invalid voice, or voice="clone" with no cloned voice saved on the account.
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
POST/api/v1/voice-change25 credits / min (60 with a cloned voice)

Voice change

Transcribes a video's speech, then fully replaces its audio track with a new synthetic voice.

Parameters

ParameterTypeDefaultDescription
uploadIdrequiredstring—Returned by POST /api/v1/uploads.
voicestringleaReplacement voice. "clone" requires a cloned voice on the account.
Values: id from GET /api/v1/voices | clone
languagestringfrLanguage spoken in the source video (ISO 639-1 code), used for the intermediate transcription.

Example request

curl -X POST https://editcaption.com/api/v1/voice-change \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE" \
  -H "Content-Type: application/json" \
  -d '{"uploadId":"3f2a9c7e-...","voice":"camille"}'

200 response

{
  "jobId": "b91c...",
  "status": "queued",
  "creditsUsed": 12,
  "creditsRemaining": 9921,
  "estimatedSeconds": 80
}

Possible errors

400
invalid_request
uploadId missing, invalid voice, voice="clone" with no cloned voice, or no speech detected in the video.
402
insufficient_credits
Credit balance lower than the job cost. The response includes balance and required.
401
unauthorized
Authorization header missing, invalid or revoked key.
500
internal_error
Unexpected server error.
GET/api/v1/jobs/{id}

Job status

Returns the state of a job started by one of the 10 tool endpoints. A job is only visible to the API key that created it (another key, even on the same account, gets 404).

Parameters

ParameterTypeDefaultDescription
idrequiredstring—jobId returned by the tool endpoint (in the URL, not the body).

Example request

curl -X GET https://editcaption.com/api/v1/jobs/JOB_ID \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE"

200 response

{
  "jobId": "b91c...",
  "status": "completed",
  "result": {
    "url": "/api/download/3f2a9c7e-...",
    "filename": "video-sous-titres.mp4"
  }
}

Possible errors

404
not_found
Unknown jobId, expired (> 3h after completion), or owned by another key.
401
unauthorized
Authorization header missing, invalid or revoked key.
  • ·result.url is a relative path: prefix it with https://editcaption.com to get a downloadable link.
  • ·The file can be downloaded several times for 3 hours after completion; it isn't a one-time link.
GET/api/v1/account

Credit balance

Returns the current credit balance (included monthly credits + purchased credits) and the email of the account that owns the API key.

Example request

curl -X GET https://editcaption.com/api/v1/account \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE"

200 response

{
  "balance": 12940,
  "purchased": 9940,
  "included": 3000,
  "includedMonthly": 3000,
  "includedRenewsAt": "2026-11-07T09:00:00.000Z",
  "email": "toi@exemple.com"
}

Possible errors

401
unauthorized
Authorization header missing, invalid or revoked key.
GET/api/v1/voices

Voice catalog

Lists the voices you can use with text-to-speech and voice-change (100+ voices in 8 languages). Pass a voice id as the voice parameter. Free.

Parameters

ParameterTypeDefaultDescription
languagestring—Filter by language (query string).
Values: fr | en | es | pt | de | it | ar | nl
genderstring—Filter by gender (query string).
Values: f | m
langstringfrLanguage of the returned descriptions.
Values: fr | en

Example request

curl -X GET https://editcaption.com/api/v1/voices \
  -H "Authorization: Bearer ecap_live_VOTRE_CLE"

200 response

{
  "voices": [
    {
      "id": "lea",
      "name": "Léa",
      "language": "fr",
      "gender": "f",
      "description": "Jeune, claire, pétillante",
      "usages": [
        "Réseaux",
        "Dynamique"
      ]
    }
  ],
  "clone": "clone"
}

Possible errors

401
unauthorized
Authorization header missing, invalid or revoked key.
  • ·"clone" isn't in the list: it's the cloned voice saved on your editcaption.com account.

Complete code examples

A complete upload → job → wait → result flow, in JavaScript and Python. Replace the example URL and API key with yours.

// Node.js 18+ (native fetch) or browser. No npm install needed.
const API_KEY = "ecap_live_YOUR_KEY";
const BASE = "https://editcaption.com";

async function call(path, body) {
  const res = await fetch(BASE + path, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error?.message ?? res.statusText);
  return data;
}

async function waitForJob(jobId) {
  while (true) {
    const res = await fetch(`${BASE}/api/v1/jobs/${jobId}`, {
      headers: { Authorization: `Bearer ${API_KEY}` },
    });
    const data = await res.json();
    if (data.status === "completed") return data.result;
    if (data.status === "failed") throw new Error(data.error);
    await new Promise((r) => setTimeout(r, 3000)); // no webhook: poll every 3s
  }
}

async function main() {
  const upload = await call("/api/v1/uploads", { url: "https://example.com/my-video.mp4" });
  const job = await call("/api/v1/subtitles", { uploadId: upload.uploadId, style: "impact" });
  const result = await waitForJob(job.jobId);
  console.log("Video ready:", BASE + result.url);
}

main();

AI agents

MCP server

EditCaption runs a remote MCP server (Streamable HTTP) at https://editcaption.com/api/mcp. Once connected, the video tools below and the agency workspace tools show up right inside your agent, nothing to install.

One-click connection (recommended)

EditCaption implements a full OAuth 2.1 authorization server (RFC 8414 + RFC 9728, Dynamic Client Registration RFC 7591) on top of the MCP server. Claude, ChatGPT and Perplexity's native custom connectors detect it automatically: paste the URL below into their "Add custom connector" screen, sign in to your EditCaption account, click "Authorize". No key to copy: an API key is created and managed for you behind the scenes (visible and revocable in My account → Developer, labeled "MCP connector"). The exact clicks per platform are on the API page.

https://editcaption.com/api/mcp

Manual alternative (without OAuth)

For an MCP client that doesn't do OAuth discovery (script, headless environment, older config…), create a key from My account → Developer (Pro and Scale plans) and pass it as a static header:

{
  "mcpServers": {
    "editcaption": {
      "url": "https://editcaption.com/api/mcp",
      "headers": { "Authorization": "Bearer ecap_live_YOUR_KEY" }
    }
  }
}

Video tools

upload_mediaFetches a file from a public URL. Returns uploadId + durationSeconds.
generate_subtitlesBurned-in automatic captions.20 credits / min.
transcribe_videoTranscription to text or SRT.15 credits / min.
clean_audioAudio clean-up.10 credits / min.
extract_audioAudio extraction (mp3/wav/aac).Free.
convert_videoFormat conversion (mp4/webm/mov/avi/mkv).Free.
merge_videosMerge several videos.Free.
add_watermarkImage or text watermark, tiled or floating.Free.
trim_videoTrim a [start, end] segment.Free.
list_voicesVoice catalog (100+ voices, 8 languages) for text_to_speech and change_voice. Free.
text_to_speechText to speech.15 credits / 1,000 chars (40 with a cloned voice).
change_voiceReplaces a video's voice.25 credits / min (60 with a cloned voice).
get_job_statusJob status (queued/processing/completed/failed).

Example prompts

  • "Upload this video https://example.com/interview.mp4 and add impact-style captions with white text."
  • "Take this video, trim the first 30 seconds, then convert the result to webm."
  • "Extract this video's audio as mp3, then transcribe it in English."
  • "Merge these three videos in this order, then add a floating "@myaccount" text watermark."

Every plan

Run your agency workspace with Claude

The same MCP server gives access to your agency workspace: your assistant reads each brand's strategy, creates posts in your calendar, adds media, schedules them and reports on analytics, with exactly the same rules as in the app (per-brand access, client approval, 30-minute lead time, TikTok options).

AccessEvery plan, the free Solo plan included, within the plan's limits (brands, members, storage). A team member only sees their own brands.
CostFree: managing brands, posts, scheduling and analytics never uses credits. Only costly video tools use them, just like in the app (see Credits & plans).
DatesISO 8601. Without an offset (2026-10-12T18:00), the time is read in the workspace time zone (whoami tool).
Auto-publishingVideo posts, connected accounts, at least 30 minutes ahead. If your client requires approval, the post must be approved by publish time. For TikTok, the assistant must ask you who can see the video (privacyLevel): it never picks it on its own.
Mediaattach_media accepts a public URL, an uploadId (upload_media) or the jobId of a finished video tool: caption a video, then add the result straight to a post.

Agency workspace tools

whoami()Signed-in account, workspace, plan, time zone, credit balances (included + purchased), auto-publish platforms, current time.
list_brands()Brands you can access: id, whether client approval is required, client language, post count, social accounts (id, network, handle).
get_brand(brandId)Everything to write for a brand: strategy, colors, current topics, ideas, to-dos, watchlist, accounts (id, connection, auto-publish available), labels, formats allowed per network.
list_posts(brandId, from?, to?, status?, includeUnscheduled?)Calendar posts over a date range (inclusive) and/or a status; includeUnscheduled adds posts without a date.
get_post(postId)Full post: caption, script, status, media (video versions, cover, images), targeted accounts and publishing state, TikTok options, comments, publication numbers.
create_post(brandId, title, type?, caption?, script?, scheduledAt?, accountIds?, labelIds?, status?)Creates a post (default format VIDEO_VERTICALE, default status A_ECRIRE). An account that doesn't support the format is rejected.
update_post(postId, title?, type?, caption?, script?, scheduledAt?, accountIds?, labelIds?, status?, correctionReason?)Only changes the fields you pass. accountIds replaces the whole list. Changing the date also moves a scheduled publication (refused if published or less than 30 min away). scheduledAt: null removes the date.
delete_post(postId, confirm: true)Permanently deletes a post and its files, after the user confirms.
attach_media(postId, role, url | uploadId | jobId, accountId?, filename?)role: final (published video, new version), cover (replaces), slide (carousel image, appended), rush (raw footage). One source only: public URL, uploadId (upload_media) or jobId of a finished video tool. accountId = account-specific version.
add_comment(postId, text, internal?)Comments on a post. internal (default true) = team note the client never sees; false = visible in their portal.
get_publish_options(postId, accountId)For one account of the post: what blocks or warns before scheduling or publishing, and for TikTok the allowed privacy levels and creator settings.
schedule_publication(postId, accountId, tiktok?)Turns on auto-publishing for the account at the post's date (at least 30 min ahead, video posts, connected accounts). tiktok = { privacyLevel (required, chosen by the user), allowComments, allowDuet, allowStitch, discloseCommercial, yourBrand, brandedContent }.
publish_now(postId, accountId, tiktok?)Publishes on this account right away (replaces a pending schedule). Same TikTok options.
cancel_publication(postId, accountId)Cancels an account's scheduled publication; the post stays in the calendar.
mark_published(postId, accountId, permalink?, published?)For a manual publication: marks the account as published (with the link); published: false undoes it.
get_brand_stats(brandId, range? (24h | 7d | 30d | 1y | all))Analytics of connected accounts: followers, views, likes, posts gained over the period vs the previous period, and per-account numbers. Default 30d.
get_account_posts(accountId, sort? (recent | best | worst), limit? (1-50))Posts of a connected account with their numbers and the account's average views. accountId comes from get_brand_stats.
get_today()Across all brands: to-dos (failed publications, posts to publish manually or overdue, reports), recent client feedback, this week's calendar.

Reference

Statuses (status)A_ECRIRE to writeA_TOURNER to shootA_MONTER to editA_VALIDER sent to the client for approvalA_CORRIGER changes requested (correctionReason)VALIDE approvedPUBLIE published
Formats (type)VIDEO_VERTICALE 9:16 video (Reel, TikTok, Shorts)VIDEO_HORIZONTALE 16:9 videoCARROUSEL image carouselIMAGE single imageSTORY storyTEXTE text only (LinkedIn, X, Threads…)
Two kinds of account idA brand's accounts (get_brand, list_brands) are used by create_post, update_post, attach_media and publishing. The connected accounts returned by get_brand_stats are only used by get_account_posts.
ErrorsA refusal comes back as a tool error (isError) with a message saying what to do and giving the link (top up, change plans, verify the email…), in the account's language: the assistant relays it as is.

Example requests

  • "Look at Maison Fleur's strategy and draft 5 posts for next week, one a day at 6 pm, on Instagram and TikTok."
  • "Caption this video in the brand's colors, add it to Thursday's post and schedule it on TikTok."
  • "Send all of this week's ready posts to my client for approval."
  • "Give me a summary of this month's TikTok analytics and tell me which formats work best."

Claude Code & AI agents

To use EditCaption as a tool in Claude Code (or any other MCP client: Claude Desktop, Cursor, Codex…), add a remote HTTP MCP server. The CLI handles OAuth for you (opens your browser, same flow as Claude.ai):

# The CLI opens your browser so you can sign in and authorize access:
# no key to type, same flow as Claude.ai / Claude Desktop.
claude mcp add --transport http editcaption https://editcaption.com/api/mcp

Without a browser (headless, CI…), pass a static key as a header instead:

# Without a browser (headless/CI environment), use a static key
# created from My account → Developer:
claude mcp add --transport http editcaption \
  https://editcaption.com/api/mcp \
  --header "Authorization: Bearer ecap_live_YOUR_KEY"

Exact option syntax may vary with your version (claude mcp add --help). For Claude Desktop or any config-file client, paste the mcpServers block from the MCP server section instead.

Once connected, just ask the agent what you want in plain language (see the examples above): it picks the right MCP tools, uploads the media, starts the job, waits for the result and adds it to your calendar.

OpenAPI / Swagger

The complete OpenAPI 3.1 schema (all REST endpoints, request/response schemas, errors) is available for download. Import it into Postman, Insomnia or the Swagger editor to generate a request collection or a client in the language of your choice.

Download openapi.json

Appendix: language codes

ISO 639-1 codes accepted by the language parameters (transcription, voice change). Use auto to let the API detect the language automatically.

autoDétection automatique
afAfrikaans
sqAlbanais
amAmharique
arArabe
hyArménien
asAssamais
azAzerbaïdjanais
baBachkir
euBasque
beBiélorusse
bnBengali
bsBosnien
brBreton
bgBulgare
myBirman
caCatalan
zhChinois
hrCroate
csTchèque
daDanois
nlNéerlandais
enAnglais
etEstonien
foFéroïen
fiFinnois
frFrançais
glGalicien
kaGéorgien
deAllemand
elGrec
guGujarati
htCréole haïtien
haHaoussa
hawHawaïen
heHébreu
hiHindi
huHongrois
isIslandais
idIndonésien
itItalien
jaJaponais
jwJavanais
knKannada
kkKazakh
kmKhmer
koCoréen
loLaotien
laLatin
lvLetton
lnLingala
ltLituanien
lbLuxembourgeois
mkMacédonien
mgMalgache
msMalais
mlMalayalam
mtMaltais
miMaori
mrMarathi
mnMongol
neNépalais
noNorvégien
nnNorvégien (Nynorsk)
ocOccitan
psPachto
faPersan
plPolonais
ptPortugais
paPendjabi
roRoumain
ruRusse
saSanskrit
srSerbe
snShona
sdSindhi
siCingalais
skSlovaque
slSlovène
soSomali
esEspagnol
suSoundanais
swSwahili
svSuédois
tlTagalog
tgTadjik
taTamoul
ttTatar
teTélougou
thThaï
boTibétain
trTurc
tkTurkmène
ukUkrainien
urOurdou
uzOuzbek
viVietnamien
cyGallois
yiYiddish
yoYoruba

A question, a specific use case?

contact@editcaption.com