Developers

Videoup API

Create personalized Videoups from your own code, Zapier, or AI agents like Claude. Get an API key in Settings → API & Agents.

Create personalized Videoups from your own code, Zapier/Make, or an AI agent. A Videoup is one of your recorded campaign videos, re-voiced and lip-synced so the greeting says the recipient's first name in your voice. Every video is checked automatically to say the right name before it becomes ready.

Base URL: https://staging.videoup.co/api/v1

Endpoints at a glance

Method Path Use it to
GET /api/v1/campaigns See your campaigns, which can make videos, and your monthly quota
POST /api/v1/videos Make a Videoup for one person (returns at once; renders in a few minutes)
GET /api/v1/videos/{id} Check a video's status and get its link once it's ready
GET /api/v1/videos List your videos, newest first
POST your URL Webhooks: we tell you when a video is ready, delivered, played, needs review or failed
POST /mcp The same actions for Claude and other AI agents (MCP)

Quick start

# 1. Find a campaign that can make videos
curl https://staging.videoup.co/api/v1/campaigns \
  -H "Authorization: Bearer YOUR_API_KEY"

# 2. Make a Videoup for someone
curl https://staging.videoup.co/api/v1/videos \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"campaign_id": 123, "first_name": "Julie", "email": "julie@acme.com"}'

# 3. A few minutes later, get the link
curl https://staging.videoup.co/api/v1/videos/9812 \
  -H "Authorization: Bearer YOUR_API_KEY"

Authentication

Create an API key in Settings → API & Agents and send it as a bearer token:

Authorization: Bearer YOUR_API_KEY

Keys last a year and can be revoked at any time. Requests are limited to 60 per minute per account. Every response is JSON.

Campaigns

GET /campaigns

Your campaigns, and whether each can make videos right now.

{
  "object": "list",
  "data": [
    {
      "id": 123,
      "object": "campaign",
      "name": "Demo follow-up",
      "can_create_videos": true,
      "not_ready_reason": null,
      "videos_count": 41,
      "created_at": "2026-10-01T14:02:11+00:00"
    }
  ],
  "quota": { "monthly_limit": 250, "used_this_month": 37 }
}

not_ready_reason is "No master video recorded yet" or "Voice clone is not ready". monthly_limit is null on unlimited plans.

Videos

POST /videos

Start a Videoup for one person.

Field Required Notes
campaign_id yes A campaign with can_create_videos: true
first_name yes Spoken in the greeting, exactly as written
email yes Identifies the person
last_name no Not spoken
idempotency_key no Defaults to campaign + email

Rendering takes a few minutes, so this returns at once:

  • 202 — started; the video's status is processing.
  • 200 — this person (same campaign and email, or same idempotency_key) already has a video; you get that one. Nothing is rendered twice.
  • 404 campaign_not_found
  • 422 cannot_create_video — e.g. Monthly AI video quota reached, Your voice clone is not ready. Calling again later retries.
  • 422 with errors — invalid input.

Each new video uses one from your monthly AI video quota. Videoup does not send anything to the person; you deliver the url.

GET /videos/{id}

GET /videos?campaign_id=&limit=&cursor=

Newest first, up to 100 per page; pass next_cursor back as cursor.

The video object

{
  "id": 9812,
  "object": "video",
  "status": "ready",
  "campaign_id": 123,
  "recipient": { "first_name": "Julie", "last_name": "Smith", "email": "julie@acme.com" },
  "url": "https://staging.videoup.co/v/aB3xK9pQ2m",
  "thumbnail_url": "https://image.mux.com/…/thumbnail.jpg?…",
  "gif_url": "https://image.mux.com/…/animated.gif?…",
  "duration_seconds": 31.2,
  "qc": { "status": "passed", "reason": null },
  "error": null,
  "plays": 2,
  "last_played_at": "2026-10-10T15:41:09+00:00",
  "source": "api",
  "created_at": "2026-10-10T15:20:00+00:00",
  "delivered_at": null
}
status Meaning
processing Rendering, or being checked. url is null.
needs_review The automatic name check wasn't sure (qc.reason says why). Approve or regenerate it on the campaign page in Videoup.
ready Passed the check. Share url.
delivered Sent by an integration (e.g. an Explee reply).
failed See error.

plays counts plays of the video after it was ready — not page loads, which email link scanners trigger.

Webhooks

Set an https endpoint in Settings → API & Agents to be told instead of polling. Each event is a POST:

{
  "id": "evt_01JA…",
  "type": "video.ready",
  "created_at": "2026-10-10T15:24:51+00:00",
  "data": { …the video object… }
}

Events: video.ready, video.delivered, video.played, video.needs_review, video.failed, and webhook.test from the settings page.

Respond with any 2xx. Anything else is retried after 1 min, 5 min, 30 min and 2 h. Endpoints must be public https URLs.

Verifying the signature

Each request has Videoup-Signature: t=<unix seconds>,v1=<hex>, where v1 = HMAC-SHA256(secret, "<t>.<raw body>") with the endpoint's signing secret (shown once when you save the endpoint). Reject requests whose t is more than 5 minutes old.

const crypto = require('crypto')
function verify(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('=')))
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false
  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1))
}

MCP (Claude and other agents)

The same three operations are available as an MCP server at https://staging.videoup.co/mcp, using the same API key:

claude mcp add --transport http videoup https://staging.videoup.co/mcp \
  --header "Authorization: Bearer YOUR_API_KEY"

Tools: list_campaigns, create_videoup, get_videoup. Then ask Claude something like "Make a Videoup for Julie Smith (julie@acme.com) from my demo campaign and draft her a follow-up email with the link."

Adding Videoup as a connector in claude.ai (which needs OAuth) is not supported yet.