videoseedvideoseed
中文

videoseed API & MCP

From minting a key to fetching analysis text and a verified processed MP4 link. The API and MCP share the web app’s credits, queue, and history. We charge actual duration only on success.

Base URL·https://www.videoseed.ccAuth·Bearer API Key (sk_…)Response·JSON · async jobsRate limit·60 req / min / key

5-minute quick start

This Node.js sample creates a link analysis job, polls every 3 seconds, and prints the result. Requires Node.js 18+.

1

Sign in and create an API Key

Open Account → API keys, name the key and create it. The secret is shown once — save it immediately.

2

Export an environment variable

export VIDEOSEED_API_KEY='YOUR_API_KEY'
3

Run the sample

Replace the Douyin URL with a real video, save as analyze.mjs, then run node analyze.mjs.

const API_KEY = process.env.VIDEOSEED_API_KEY;
const BASE_URL = "https://www.videoseed.cc";

const created = await fetch(`${BASE_URL}/api/v1/analyze`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://www.douyin.com/video/VIDEO_ID",
  }),
});

if (!created.ok) throw new Error(await created.text());
const job = await created.json();

while (true) {
  await new Promise((resolve) => setTimeout(resolve, 3000));
  const response = await fetch(`${BASE_URL}/api/v1/jobs/${job.id}`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  if (!response.ok) throw new Error(await response.text());

  const current = await response.json();
  if (current.status === "done") {
    console.log(current.result);
    break;
  }
  if (current.status === "error" || current.status === "cancelled") {
    throw new Error(current.error_code ?? "ANALYSIS_FAILED");
  }
}

Create and manage API Keys

An API Key represents your account. Do not put it in front-end code, public repos, or logs. Revoke and mint a new one if it leaks. Web session cookies cannot call /api/v1/*; API Keys cannot call web /api/*. Key management lives on the Account page.

  1. Sign in to the web app.
  2. Create a key under Account → API keys and narrow scopes if needed.
  3. Copy the secret once and store it in server env.

You will be asked to sign in if needed; create and revoke happen on the Account page.

HTTP API

All business endpoints use Authorization: Bearer YOUR_API_KEY. Requests and responses are JSON except the presigned upload URL.

Analyze a video link

Supports Douyin, Xiaohongshu, and Bilibili pages/short links. For other platforms, download first and use the upload flow.

curl -X POST 'https://www.videoseed.cc/api/v1/analyze' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://www.douyin.com/video/VIDEO_ID"}'

Response: 202 Accepted

{
  "id": "c9aa82c5-79ac-4cb8-9a91-9223dc83b6b8",
  "status": "queued",
  "queued": true
}

Upload and analyze a local file

MP4, MOV, WebM, M4V. Max 1024 MB; files over ~300 MB must be ≤ 30 minutes. Bytes go straight to object storage.

# 1. Presigned upload URL
curl -X POST 'https://www.videoseed.cc/api/v1/uploads' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"filename":"video.mp4","size_bytes":12345678}'

# 2. PUT the file to upload_url
curl -X PUT --upload-file './video.mp4' 'UPLOAD_URL'

# 3. Analyze with upload_key
curl -X POST 'https://www.videoseed.cc/api/v1/analyze' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"upload_key":"UPLOAD_KEY","title":"video.mp4"}'

Upload address response: 201 Created

{
  "upload_key": "uploads/USER_ID/FILE_ID.mp4",
  "upload_url": "https://storage.example.com/...",
  "method": "PUT",
  "expires_in": 1800,
  "max_bytes": 1073741824
}

Optional dims

Defaults apply when omitted. Pass a full dims object only when you need to steer output.

FieldValuesDefault
modelflagship, gemini, doubao, gptgemini
videoTypegeneral, short, dance, ecommerce, script, drama, animegeneral
targetModelallRef, firstFrame, firstFrameRefallRef
beatModedialogue, actiondialogue
maxSegmentSecinteger seconds 5–120 (web UI: 15 / 30 / custom)15

Endpoint list

MethodPath
POST/api/v1/analyzesubmit url or upload_key
POST/api/v1/uploadspresigned PUT
GET/api/v1/jobs/{id}status and result
GET/api/v1/jobs/{id}/video-linkplay / download
GET/api/v1/jobshistory (cursor)
POST/api/v1/analyses/batchbatch ≤8
GET/api/v1/capabilitieslimits
GET/api/v1/creditscredits
GET/api/v1/usageusage ledger
POST/api/v1/jobs/{id}/retryretry
POST/api/v1/jobs/{id}/cancelcancel
POST / GET / DELETE/api/v1/webhooks…async notifications
POST/api/mcpMCP JSON-RPC

Credits

curl 'https://www.videoseed.cc/api/v1/credits' \
  -H 'Authorization: Bearer YOUR_API_KEY'
{
  "balanceSec": 1800,
  "isPro": true,
  "activePacks": 1
}

Async jobs and results

Keep the returned id. Poll every 3 seconds; stop on done, error, or cancelled. Client-side wait of ~30 minutes is a reasonable upper bound.

curl 'https://www.videoseed.cc/api/v1/jobs/JOB_ID' \
  -H 'Authorization: Bearer YOUR_API_KEY'
statusMeaning
queuedIn queue
analyzingParsing, ASR, generating result
doneSuccess; result set; charged actual seconds
errorFailed; no charge; error_code set
cancelledCancelled; unused reservation released

Success body

{
  "id": "c9aa82c5-79ac-4cb8-9a91-9223dc83b6b8",
  "status": "done",
  "source_kind": "link",
  "title": "Sample",
  "result": { "text": "Full analysis text" },
  "error_code": null,
  "charged_seconds": 15,
  "created_at": "2026-07-29T08:00:00.000Z",
  "updated_at": "2026-07-29T08:02:10.000Z"
}

Error body

{
  "id": "c9aa82c5-79ac-4cb8-9a91-9223dc83b6b8",
  "status": "error",
  "source_kind": "file",
  "title": "video.mp4",
  "result": null,
  "error_code": "ASR_FAILED",
  "charged_seconds": null,
  "created_at": "2026-07-29T08:00:00.000Z",
  "updated_at": "2026-07-29T08:01:20.000Z"
}

On-demand video link

done jobs do not embed a URL in history or the result. Call on demand. play returns a durable R2 custom-domain URL (https://r2.videoseed.cc/…; expires_in is kept for compatibility) and skips S3 HEAD; download is still a short-lived presigned URL with Content-Disposition (10 minutes) after HEAD verifies video/mp4.

curl 'https://www.videoseed.cc/api/v1/jobs/JOB_ID/video-link?mode=play' \
  -H 'Authorization: Bearer YOUR_API_KEY'

curl 'https://www.videoseed.cc/api/v1/jobs/JOB_ID/video-link?mode=download' \
  -H 'Authorization: Bearer YOUR_API_KEY'
{
  "url": "https://r2.videoseed.cc/upload/<sha>/video/source.mp4",
  "mode": "play",
  "expires_in": 1800,
  "expires_at": "2026-08-10T00:30:00.000Z",
  "content_type": "video/mp4",
  "filename": "sample.mp4"
}

History, batch, and usage

History uses a stable keyset cursor and returns card fields only. Treat cursor as opaque.

History

GET https://www.videoseed.cc/api/v1/jobs?limit=20&status=done
Authorization: Bearer YOUR_API_KEY

Response: items / has_more / next_cursor

Batch + idempotency

POST https://www.videoseed.cc/api/v1/analyses/batch
Idempotency-Key: batch-20260805-01
body: { items: [{ client_reference_id, upload_key | url, title, dims }] }

Max 8 items. Same key + same body replays the first response; different body → 409 IDEMPOTENCY_CONFLICT.

Capabilities, usage, retry, cancel

GET /api/v1/capabilities (video_links: play 1800s, download 600s)
GET /api/v1/usage?limit=20
POST /api/v1/jobs/{id}/retry
POST /api/v1/jobs/{id}/cancel

usage is an append-only ledger: analysis_charge negative; credit_purchase / reservation_release positive. Only error is retryable; only queued / analyzing are cancellable.

Webhook

On completion or failure, events go to a DB outbox first, then an independent dispatcher delivers them. Delivery failures do not change job status.

Requires scope webhooks:manage.

POST /api/v1/webhooks
{ "url": "https://your-server.example/hook", "events": ["analysis.completed", "analysis.failed"] }
→ 201; secret is returned once (whsec_…)

GET /api/v1/webhooks → list (no secret)
DELETE /api/v1/webhooks/{id} → { "ok": true }

URL must be HTTPS and public. localhost, private, link-local, and metadata addresses are rejected (400 WEBHOOK_INVALID_URL).
The dispatcher does not follow redirects.

Headers: X-Videoseed-Event-Id, X-Videoseed-Delivery-Id, X-Videoseed-Timestamp, X-Videoseed-Signature
Signature: sha256=HMAC_SHA256(secret, timestamp + "." + rawBody)
Non-2xx / timeouts retry with exponential backoff, up to 8 attempts then failed.
// Receiver: verify before JSON.parse; reject timestamps >5 minutes old; dedupe by event_id
const ts = req.headers['x-videoseed-timestamp'];
const sig = req.headers['x-videoseed-signature'];
const raw = await readRawBody(req);
if (!verifyHmac(secret, ts, raw, sig)) return res.status(401).end();
const payload = JSON.parse(raw);

MCP

Remote MCP URL: https://www.videoseed.cc/api/mcp. For clients that support remote HTTP MCP and custom Authorization headers.

1

Create an API Key

Prefer a dedicated MCP key so you can revoke it alone.

2

Add to the MCP client

Claude Code can use the command below. Other clients should merge the JSON into existing mcpServers — do not overwrite.

claude mcp add --transport http videoseed 'https://www.videoseed.cc/api/mcp' \
  --header 'Authorization: Bearer YOUR_API_KEY'
{
  "mcpServers": {
    "videoseed": {
      "url": "https://www.videoseed.cc/api/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_API_KEY"
      }
    }
  }
}
3

Reload and verify

Reload the MCP server, then ask for remaining quota. A success path calls get_quota and returns balanceSec.

Connectivity without the client

If the client fails to connect, verify URL and key with this request. A JSON-RPC result means the wire is fine.

curl -X POST 'https://www.videoseed.cc/api/mcp' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc":"2.0",
    "id":1,
    "method":"tools/call",
    "params":{"name":"get_quota","arguments":{}}
  }'

Tools

ToolArgsPurpose
get_quotacredits
create_video_uploadfilename, size_bytespresigned PUT
analyze_videourl | upload_key; title?, dims?create job
get_analysisidjob status
get_video_linkid, mode=play|downloadR2 MP4 URL
list_analyseslimit?, cursor?, status?job history
analyze_videositems ≤8batch
get_capabilitieslimits
list_usagelimit?, cursor?, type?usage ledger
retry_analysisidretry
cancel_analysisidcancel

get_video_link only returns a URL when the job is done and the object still exists; it never exposes storage keys. play is a durable r2.videoseed.cc URL (sha256 path) until GC; download stays short-lived and presigned. Local files: create_video_upload → HTTP PUT → analyze_video with upload_key.

Errors

HTTP errors return code, message, and request_id. When contacting support, include request_id, job id, and time — never the full API Key.

{
  "code": "QUOTA_INSUFFICIENT",
  "message": "额度不足,请充值",
  "request_id": "82d64113-09b0-473b-a7b5-1f11bbb08f64"
}
HTTPcodeWhat to do
400VALIDATIONBad fields, or both url and upload_key
400LINK_UNSUPPORTEDUnsupported link platform
400VIDEO_INVALIDUnrecognized video
400WEBHOOK_INVALID_URLWebhook URL is not HTTPS public
401API_KEY_INVALIDBad/revoked key or credential mismatch
402QUOTA_INSUFFICIENTOut of credits
403FORBIDDENForeign upload_key or missing scope
404NOT_FOUNDJob missing or not yours
404VIDEO_NOT_AVAILABLENo playable object
409IDEMPOTENCY_CONFLICTSame Idempotency-Key, different body
409JOB_NOT_RETRYABLE / JOB_NOT_CANCELLABLEWrong status
429RATE_LIMITEDToo fast (>60/min)
502LINK_FETCH_FAILED / ASR_FAILED / AI_FAILEDUpstream failure
500 / 503INTERNAL / PROVIDER_DOWN / WEBHOOK_SECRET_UNAVAILABLETemporary outage

Safe to retry automatically: 429, 500, 502, 503 (2s / 4s / 8s, max 3). Do not blind-retry: 400, 401, 402, 404, 422.