← vidshark.ai

VidShark API

Generate cinematic faceless explainer videos from a one-line idea. Public REST API designed agent-first: every endpoint is documented in OpenAPI 3.1, errors are self-describing, POSTs accept Idempotency-Key for safe retries.

Quickstart

  1. Get an API key from Dashboard → Settings → API keys. Format: vsk_live_…
  2. Send it as Authorization: Bearer <key> on every request.
  3. Submit a render with POST /api/v1/videos.
  4. Poll GET /api/v1/videos/{id} every 10-20s until status === "ready".
  5. Play final_video_url.

Create a video — curl

curl -X POST https://vidshark.ai/api/v1/videos \
  -H "Authorization: Bearer $VIDSHARK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "idea": "Why the Persian Empire fell — Pixar-style animated explainer",
    "category": "story",
    "duration": 16,
    "aspect_ratio": "9:16"
  }'

Returns 202 with a Video resource. Cost: duration / 8 credits up front. Failed scenes auto-refund.

Poll until ready — TypeScript

async function waitForVideo(id: string) {
  const key = process.env.VIDSHARK_API_KEY!;
  while (true) {
    const r = await fetch(`https://vidshark.ai/api/v1/videos/${id}`, {
      headers: { Authorization: `Bearer ${key}` },
    });
    const { video } = await r.json();
    if (video.status === "ready")  return video.final_video_url;
    if (video.status === "failed") throw new Error("Render failed");
    await new Promise(r => setTimeout(r, 10_000)); // 10s
  }
}

Webhooks (skip the polling)

Instead of polling, register an HTTPS endpoint and we'll push events as the render moves through its states. Each request is signed with HMAC-SHA256 so you can trust the sender without IP allowlists.

Create a subscription:

curl -X POST https://vidshark.ai/api/v1/webhooks \
  -H "Authorization: Bearer $VIDSHARK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "n8n production",
    "url":  "https://hooks.example.com/vidshark",
    "events": ["video.ready", "video.failed"]
  }'

# Response includes "secret": "whsec_…" — store it now, shown once.

Event types:

  • video.created — render queued.
  • video.scene_ready — one scene finished (multi-clip videos emit one per scene).
  • video.ready — final stitched MP4 ready.
  • video.failed — render hit an unrecoverable error.
  • * — wildcard, subscribe to everything.

Example payload (video.ready):

{
  "id":   "evt_b1c2…",
  "type": "video.ready",
  "created_at": "2026-05-13T10:23:14.001Z",
  "data": {
    "video_id":            "8e9f7a…",
    "final_video_url":     "https://r2.vidshark.ai/…/final.mp4?sig=…",
    "narration_audio_url": "https://r2.vidshark.ai/…/narration.mp3?sig=…",
    "clip_count": 2
  }
}

Verify the VidShark-Signature header (format t=<unix>,v1=<hex>):

import { createHmac, timingSafeEqual } from "node:crypto";

const TOLERANCE_S = 300; // reject anything older than 5 minutes

export function verifyVidSharkWebhook(
  rawBody: string,
  header: string,
  secret: string,
): boolean {
  const parts = Object.fromEntries(
    header.split(",").map(p => p.split("=") as [string, string]),
  );
  const t  = Number(parts.t);
  const v1 = parts.v1;
  if (!Number.isFinite(t) || !v1) return false;
  if (Math.abs(Date.now() / 1000 - t) > TOLERANCE_S) return false;

  const expected = createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");

  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(v1, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}

Delivery is at-least-once. We retry non-2xx responses at 1m / 5m / 30m / 2h / 6h / 24h, then auto-disable the subscription after 6 consecutive failures. Respond 2xx within 10s — slower responders look like failures. Inspect recent attempts with GET /api/v1/webhooks/{id}/deliveries or fire a synthetic test with POST /api/v1/webhooks/{id}/test.

Errors

Every error has the same shape:

{
  "code":     "insufficient_credits",
  "message":  "Need 6 credits, you have 2. Top up or pick a shorter length.",
  "docs_url": "https://vidshark.ai/docs/api#insufficient_credits",
  "details":  { "credits_required": 6, "credits_remaining": 2 }
}

Pattern-match on code — it's stable. Full enum + per-endpoint codes are in the OpenAPI spec.

Discovery for agents

  • GET /llms.txt — human-readable summary tuned for LLM ingestion.
  • GET /api/v1/openapi.json — full machine-readable contract.
  • GET /.well-known/openapi.json — alias to the spec for agents that probe the standard location.

Limits + costs

  • 1 credit = 1 scene render (8s). Length × 1/8 credits per video.
  • Failed scenes refund automatically. Multi-scene videos with any failed sibling refund the successful ones too — you're never charged for an unfinishable render.
  • Idempotency window: 24 hours per Idempotency-Key.
  • Per-key auth rate limit: ~60 req/min. Burst handled gracefully.