Skip to main content

Overview

The Video API allows you to manage videos, check transcription status, retrieve analytics, and delete videos.

Endpoints

Get Transcribe Status

Check the transcription status of a video.
GET /api/video/transcribe/status
videoId
string
required
The unique identifier of the video

Response

transcriptionStatus
string | null
Current transcription status. Can be:
  • "PROCESSING" - Transcription in progress
  • "COMPLETE" - Transcription finished
  • "ERROR" - Transcription failed
  • null - Transcription not started

Example Request

curl -X GET "https://cap.so/api/video/transcribe/status?videoId=abc123" \
  -H "Authorization: Bearer <token>"

Example Response

{
  "transcriptionStatus": "COMPLETE"
}

Delete Video

Permanently delete a video.
DELETE /api/video/delete
videoId
string
required
The unique identifier of the video to delete

Response

success
unknown
Empty response on success

Example Request

curl -X DELETE "https://cap.so/api/video/delete?videoId=abc123" \
  -H "Authorization: Bearer <token>"

Example Response

{}
This action is permanent and cannot be undone. The video and all associated data will be deleted.

Get Analytics

Retrieve view count and analytics for a video.
GET /api/video/analytics
videoId
string
required
The unique identifier of the video

Response

count
number
Total number of views for the video

Example Request

curl -X GET "https://cap.so/api/video/analytics?videoId=abc123" \
  -H "Authorization: Bearer <token>"

Example Response

{
  "count": 147
}

Desktop Video Endpoint

The desktop app has an additional video deletion endpoint.

Delete Video (Desktop)

DELETE /api/desktop/video/delete
videoId
string
required
The unique identifier of the video to delete
authorization
string
required
Bearer token for authentication

Example Request

curl -X DELETE "https://cap.so/api/desktop/video/delete?videoId=abc123" \
  -H "Authorization: Bearer <token>"

Video Schema

Videos in the database follow this structure:

Video Object

interface Video {
  id: string;
  ownerId: string;
  name: string;
  createdAt: Date;
  totalComments: number;
  totalReactions: number;
  public: boolean;
  source: "local" | "s3";
  transcriptionStatus: "PROCESSING" | "COMPLETE" | "ERROR" | null;
  metadata: VideoMetadata;
}

Video Metadata

interface VideoMetadata {
  customCreatedAt?: string;
  sourceName?: string;
  aiTitle?: string;
  summary?: string;
  chapters?: { title: string; start: number }[];
  aiGenerationStatus?: "QUEUED" | "PROCESSING" | "COMPLETE" | "ERROR" | "SKIPPED";
  enhancedAudioStatus?: "PROCESSING" | "COMPLETE" | "ERROR" | "SKIPPED";
}

Error Responses

401 Unauthorized

{
  "error": "Unauthorized"
}
Authentication required or token invalid.

404 Not Found

{
  "error": "Video not found"
}
The requested video does not exist or you don’t have permission to access it.

500 Internal Server Error

{
  "error": "Internal server error",
  "message": "Failed to process request"
}
An unexpected error occurred on the server.

Implementation Details

The video endpoints are defined in packages/web-api-contract/src/index.ts:63-90:
video: c.router({
  getTranscribeStatus: {
    method: "GET",
    path: "/video/transcribe/status",
    query: z.object({ videoId: z.string() }),
    responses: {
      200: z.object({
        transcriptionStatus: z
          .custom<"PROCESSING" | "COMPLETE" | "ERROR">()
          .nullable(),
      }),
    },
  },
  delete: {
    method: "DELETE",
    path: "/video/delete",
    query: z.object({ videoId: z.string() }),
    responses: { 200: z.unknown() },
  },
  getAnalytics: {
    method: "GET",
    path: "/video/analytics",
    query: z.object({ videoId: z.string() }),
    responses: {
      200: z.object({ count: z.number() }),
    },
  },
})

Rate Limiting

Currently, there are no rate limits on video endpoints for self-hosted instances. The production instance may implement rate limiting in the future.

Next Steps

Authentication

Learn about authentication methods

Notifications

Manage user notifications

Build docs developers (and LLMs) love