framefetch-net Extract API

The Extract API from framefetch-net — 1 operation(s) for extract.

Operations 1

POST /v1/extract Extract data from a video URL #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/framefetch-net:framefetch-net-extract-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

framefetch-net-extract-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Framefetch Net Extract API
  version: 1.7.0
  contact:
    name: FrameFetch
    url: https://framefetch.net
  termsOfService: https://framefetch.net/impressum
  description: 'Operations tagged Extract across 2 of this provider''s published API definitions: openapi.json, framefetch-net-openapi.json. Each path carries the servers of the definition it was published in.'
servers:
- url: https://framefetch.net
security:
- bearerAuth: []
tags:
- name: Extract
paths:
  /v1/extract:
    post:
      operationId: extract
      summary: Extract data from a video URL
      parameters:
      - $ref: '#/components/parameters/FormatMd'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ExtractRequest'
      responses:
        '200':
          description: 'Extraction result. Returned as Markdown (Content-Type: text/plain) instead of JSON when ?format=md is set or an Accept: text/plain / text/markdown header is sent; returned as SubRip/WebVTT (Content-Type: application/x-subrip / text/vtt) when ?format=srt|vtt is set.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ExtractResult'
            text/plain:
              schema:
                type: string
                description: Markdown rendering of the ExtractResult.
            application/x-subrip:
              schema:
                type: string
                description: SubRip (.srt) rendering of the transcript's timed segments (?format=srt).
            text/vtt:
              schema:
                type: string
                description: WebVTT (.vtt) rendering of the transcript's timed segments (?format=vtt).
        '400':
          $ref: '#/components/responses/Error'
        '401':
          $ref: '#/components/responses/Error'
        '402':
          $ref: '#/components/responses/Error'
        '409':
          description: SUBTITLES_UNAVAILABLE — ?format=srt|vtt was requested but the (possibly cached) result carries no timed transcript segments to build subtitles from.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/Error'
      tags:
      - Extract
    servers:
    - url: https://framefetch.net
components:
  schemas:
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            hint:
              type: string
    VideoComments:
      type: object
      description: 'Up to cap_applied TOP-LEVEL comments for a video, sorted by the platform''s "top" ranking (present only when "comments" was requested). Supported on YouTube only (via yt-dlp''s info-json comments). Reddit''s own public comment source — the unauthenticated thread JSON API — worked the same way until Reddit deprecated unauthenticated access to it on 2026-05-28; TikTok/Instagram/Pinterest never had a reliable public comment source. Billed a flat $0.0045 per call (independent of comments_cap), charged only when comments were actually produced. Best-effort: any fetch/parse failure, or an unsupported platform, omits the whole field with a warning and is NOT charged — never surfaces as an HTTP error code. Worker-internal failure codes behind those warnings (never an HTTP error, only a warnings[] string): COMMENTS_UNSUPPORTED (the platform has no comment source — drop "comments" from fields for it; see GET /v1/platforms), COMMENTS_PROVIDER_ERROR (the yt-dlp info-json fetch or parse failed).'
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/VideoComment'
        total_fetched:
          type: integer
          description: How many comments actually came back (after the cap).
        cap_applied:
          type: integer
          description: The effective cap that was applied (default 30, hard max 200 via comments_cap).
        sort:
          type: string
          enum:
          - top
    CommentSentiment:
      type: object
      description: 'Aggregated LLM sentiment over a video''s comments (present only when "comment_sentiment" was requested, which auto-includes "comments" as its input): ONE Groq chat call (llama-3.3-70b-versatile, temperature 0, JSON mode) reads up to 100 comments and returns the audience mood AS A WHOLE — not per-comment scoring. Requires at least 5 fetched comments; fewer (or a model/parse failure) omits the whole field with a warning and is NOT charged — never surfaces as an HTTP error code. Billed a flat $0.006 per call, on top of the $0.0045 "comments" call it rides on. No competitor offers this rollup.'
      properties:
        positive_pct:
          type: number
          description: 0-100; positive_pct + neutral_pct + negative_pct === 100 (normalized).
        neutral_pct:
          type: number
        negative_pct:
          type: number
        summary:
          type: string
          description: 2-3 plain English sentences characterizing the overall audience reaction.
        top_themes:
          type: array
          items:
            type: string
          description: Up to 5 short recurring themes across the comments.
        representative:
          type: object
          description: One exemplar comment per polarity, when found.
          properties:
            positive:
              type: string
            negative:
              type: string
    ExtractRequest:
      type: object
      required:
      - url
      properties:
        url:
          type: string
          format: uri
        fields:
          type: array
          items:
            type: string
            enum:
            - metadata
            - insights
            - transcript
            - frames
            - text_overlay
            - digest
            - audio_digest
            - structured
            - comments
            - comment_sentiment
            - delta
          default:
          - metadata
          description: 'digest (LLM summary of the transcript) auto-includes transcript and degrades gracefully if none is available. audio_digest (a spoken mp3 briefing synthesized from the digest gist) auto-includes digest (and thus transcript); it returns a time-limited signed URL plus the voice/provider used, is billed per estimated spoken second only when the mp3 is actually produced, and degrades to a warning (never charged, never a hard error) when no TTS provider is configured or the requested language isn''t supported by the only configured provider. When translate is also set, the digest is generated directly in that target language so the audio speaks it too — combine audio_digest with translate for a foreign-language briefing from one call. structured (typed JSON understanding of the video: chapters, entities, products_shown, claims, key_moments) auto-includes transcript and also triggers the engine''s own keyframe pass over the source video, so it works even on caption-less sources; a single gpt-4o-mini vision call over the transcript plus up to 12 sampled keyframes, run at temperature 0 so the result is deterministic and cacheable; a flat $0.03 per video, charged only when the analysis is actually produced (a download/VLM/parse failure omits the field with a warning and is NOT charged — see StructuredError codes STRUCTURED_UNAVAILABLE, STRUCTURED_PROVIDER_ERROR, STRUCTURED_PARSE_ERROR on VideoStructured below). comments returns up to comments_cap top-level comments per video ({ items: [{ text, author?, like_count?, reply_count? }], total_fetched, cap_applied, sort:"top" }); it is INDEPENDENT of the transcript (no download) and available on YouTube only — Reddit''s unauthenticated comment API was deprecated on 2026-05-28 and now returns a hard 403, so Reddit omits the field exactly like TikTok/Instagram/Pinterest, with a warning and never a charge (see GET /v1/platforms and COMMENTS_UNSUPPORTED on VideoComments below). Author is a display handle only (no user ids/urls). Flat $0.0045 per call, charged only when comments were actually produced. comment_sentiment (aggregated audience sentiment: percentages, themes, summary — ONE LLM pass over the comments) auto-includes comments (its input; same YouTube-only availability, Reddit''s source having been deprecated) and needs at least 5 fetched comments — fewer, or a model/parse failure, omits it with a warning and is never charged (see CommentSentiment below). Flat $0.006 per call, on top of the comments call it rides on. No competitor offers this rollup. delta (change vs the most-recent prior fetch of the same url: engagement velocity per hour + title/thumbnail-change flags) is never cached and returns hasPrior:false the first time a url is seen. text_overlay (on-screen text via OCR) requires frames to also be requested, with a frames spec. Auto-skipped with a warning above 200 estimated frames.'
        frames:
          $ref: '#/components/schemas/FrameSpec'
        verbosity:
          type: string
        translate:
          type: string
          description: 'Optional ISO-639-1 target language code (e.g. "es", "de", "ja") to also translate the transcript into, surfaced as transcript_translated (with timings preserved when the source transcript had them). Requires "transcript" in fields (or "digest", which pulls transcript in). Billed per audio-minute like transcription — even for caption-sourced transcripts, since the translation is a separate LLM pass. Supported: en, es, de, fr, pt, it, nl, pl, tr, ru, uk, ar, hi, id, vi, th, ja, ko, zh, sv, da, no, fi, cs, ro (25 languages).'
        voice:
          type: string
          enum:
          - alloy
          - echo
          - fable
          - onyx
          - nova
          - shimmer
          - Fritz-PlayAI
          default: alloy
          description: 'Spoken voice for the "audio_digest" field: the six OpenAI gpt-4o-mini-tts voices (alloy, echo, fable, onyx, nova, shimmer — multilingual) plus Groq/PlayAI''s "Fritz-PlayAI" (English/Arabic-only fallback, used when no OpenAI key is configured). Defaults to "alloy". Inert unless "audio_digest" is requested; an unlisted value is a typed 400 that echoes this allowlist.'
        comments_cap:
          type: integer
          minimum: 1
          maximum: 200
          default: 30
          description: Max number of top-level comments the "comments" field returns (1–200, default 30). Inert unless "comments" (or "comment_sentiment", which auto-includes it) is requested; a value outside 1–200 is a 400 INVALID_PARAMS.
        publish:
          type: boolean
          default: false
          description: Opt in to a public, shareable per-video SEO page at /v/<id> (a stable hash of the url). Publishes ONLY public metadata plus a short fair-use transcript excerpt — never the full transcript or a signed frame URL. Pages carry VideoObject structured data and are listed in /sitemap-videos.xml. Best-effort; never affects the API response.
    TranscriptSegment:
      type: object
      description: 'One timed transcript segment: start/end offsets in seconds (floats, relative to the video start) and the segment''s text.'
      required:
      - start
      - end
      - text
      properties:
        start:
          type: number
        end:
          type: number
        text:
          type: string
    VideoStructured:
      type: object
      description: 'Typed, structured understanding of a video (present only when "structured" was requested): the transcript plus up to 12 sampled keyframes are run through a vision LLM (gpt-4o-mini, temperature 0) that returns chapters, entities, products shown, claims, and key moments as strict JSON. Deterministic and cacheable — unlike audio_digest it carries no expiring signed URL, so it takes part in the normal content-hash cache. Best-effort like digest: any download/VLM/parse failure omits the whole field, adds a warning to the top-level warnings array, and is NOT charged; the rest of the extraction stays usable. Worker-internal failure codes (never surfaced as an HTTP error, only as a warnings[] string): STRUCTURED_UNAVAILABLE (no vision provider configured — OPENAI_API_KEY unset), STRUCTURED_PROVIDER_ERROR (the provider returned a non-2xx response), STRUCTURED_PARSE_ERROR (the model''s output could not be parsed/validated into this schema). Billed a flat $0.03 per video (perStructuredVideoMicros, floor-pinned — see /pricing) charged only when the analysis is actually produced.'
      properties:
        chapters:
          type: array
          description: Timespan segments of the video.
          items:
            type: object
            properties:
              start_sec:
                type: number
              end_sec:
                type: number
              title:
                type: string
              summary:
                type: string
        entities:
          type: array
          description: People/orgs/places/products/other the model saw or heard.
          items:
            type: object
            properties:
              name:
                type: string
              type:
                type: string
                enum:
                - person
                - org
                - place
                - product
                - other
        products_shown:
          type: array
          description: Products/brands the video shows and/or talks about.
          items:
            type: object
            properties:
              name:
                type: string
              evidence:
                type: string
                enum:
                - visual
                - spoken
                - both
                description: 'How the product was surfaced: only on-screen, only mentioned, or both.'
        claims:
          type: array
          description: Factual claims made in the video, optionally anchored to a timestamp.
          items:
            type: object
            properties:
              text:
                type: string
              timestamp_sec:
                type: number
        key_moments:
          type: array
          description: Notable moments (hooks, reveals, demo steps) at a specific second.
          items:
            type: object
            properties:
              timestamp_sec:
                type: number
              description:
                type: string
        keyframe_mode:
          type: string
          enum:
          - scene
          - uniform
          description: 'How the analyzed frames were selected: ''scene'' = content-aware cut detection, ''uniform'' = even-sampling fallback for static/short clips with too few detected cuts.'
    ExtractResult:
      type: object
      properties:
        platform:
          type: string
        url:
          type: string
        metadata:
          type: object
          properties:
            title:
              type:
              - string
              - 'null'
            uploader:
              type:
              - string
              - 'null'
            durationSec:
              type:
              - number
              - 'null'
            uploadDate:
              type:
              - string
              - 'null'
              description: normalized YYYY-MM-DD
            sourceFps:
              type:
              - number
              - 'null'
            thumbnail:
              type:
              - string
              - 'null'
              description: poster/cover image URL (additive; may be null or omitted for older callers).
        insights:
          type: object
        transcript:
          type: object
          properties:
            text:
              type: string
            source:
              type: string
            lang:
              type: string
              description: Best-effort source language code, when known.
            segments:
              type: array
              description: 'Timed transcript segments (Whisper verbose_json or caption cue timings). Additive: omitted entirely (never []) when the source carries no usable timings.'
              items:
                $ref: '#/components/schemas/TranscriptSegment'
        transcript_translated:
          type: object
          description: Present only when the caller passed the `translate` param. An LLM translation of the transcript into the requested ISO-639-1 language, billed per audio-minute like transcription.
          properties:
            lang:
              type: string
              description: The requested ISO-639-1 target language.
            text:
              type: string
            segments:
              type: array
              description: Mirrors the source cue timings (start/end unchanged, text translated); omitted when the source transcript carried no timings — never back-filled from the untranslated transcript.
              items:
                $ref: '#/components/schemas/TranscriptSegment'
        digest:
          type: object
          description: LLM summary of the transcript (present only when the digest field was requested and a transcript was available).
          properties:
            gist:
              type: string
            topics:
              type: array
              items:
                type: string
            state:
              type: object
        audio_digest:
          $ref: '#/components/schemas/AudioDigest'
        structured:
          $ref: '#/components/schemas/VideoStructured'
        comments:
          $ref: '#/components/schemas/VideoComments'
        comment_sentiment:
          $ref: '#/components/schemas/CommentSentiment'
        delta:
          type: object
          description: 'Change since the most-recent prior fetch of the same url (present only when the delta field was requested). First time a url is seen -> { hasPrior: false } and nothing else. A per-hour rate is null when a counter was unavailable or no time had elapsed.'
          properties:
            hasPrior:
              type: boolean
            sinceTs:
              type: integer
              description: epoch ms of the prior snapshot this delta is measured against
            viewsPerHr:
              type:
              - number
              - 'null'
            likesPerHr:
              type:
              - number
              - 'null'
            commentsPerHr:
              type:
              - number
              - 'null'
            titleChanged:
              type: boolean
            thumbnailChanged:
              type: boolean
        frames:
          type: array
          items:
            type: object
            properties:
              index:
                type: integer
              url:
                type: string
              tSec:
                type: number
        textOverlay:
          type: array
          description: On-screen text per frame (OCR), same index as frames.
          items:
            type: object
            properties:
              index:
                type: integer
              text:
                type: string
              lines:
                type: array
                items:
                  type: object
                  properties:
                    text:
                      type: string
                    confidence:
                      type: number
                    bbox:
                      type: array
                      items:
                        type: number
                      minItems: 4
                      maxItems: 4
        cost:
          type: object
          properties:
            totalMicros:
              type: integer
            breakdownMicros:
              type: object
    VideoComment:
      type: object
      description: 'One top-level comment. Data-minimized by design: only the comment text, the author''s DISPLAY handle (never a user id, profile URL, or avatar), the like count, and the number of direct replies — all optional except text, omitted when the source doesn''t provide them.'
      required:
      - text
      properties:
        text:
          type: string
        author:
          type: string
          description: Display handle only — no user id / profile URL (data minimization).
        like_count:
          type: integer
        reply_count:
          type: integer
          description: Number of direct replies to this top-level comment.
    AudioDigest:
      type: object
      description: 'A spoken-audio rendering of the video''s digest (present only when "audio_digest" was requested and a digest was available to synthesize). Never served from the content-hash cache — its signed URL expires and the voice can vary per request. Billed per estimated spoken second (from the digest text length, ~15 chars/s) ONLY when the mp3 is actually produced; a TTS/upload failure omits this field, adds a warning to the top-level warnings array, and is not charged — the rest of the extraction stays usable. Failure reasons include no TTS provider configured (analogous to the worker-internal TTS_UNAVAILABLE code: neither OPENAI_API_KEY nor GROQ_API_KEY set) and an unsupported language on the only configured provider (TTS_LANG_UNSUPPORTED: Groq/PlayAI only speaks English/Arabic — set an OpenAI key for other languages); neither surfaces as an HTTP error code, only as a warnings[] string.'
      properties:
        url:
          type: string
          description: Signed URL to the mp3 (24h TTL).
        seconds:
          type: number
          description: Estimated spoken duration (digest gist chars / 15), the billing basis — not measured from the mp3.
        voice:
          type: string
          description: The TTS voice actually used (after per-provider fallback/mapping).
        provider:
          type: string
          enum:
          - openai
          - groq
        lang:
          type: string
          description: ISO-639-1 language the audio is spoken in; present only when a translate target drove a target-language digest.
    FrameSpec:
      type: object
      properties:
        mode:
          type: string
          enum:
          - all
          - every_n
          - fps
          - range
        n:
          type: integer
          minimum: 1
        fps:
          type: number
          maximum: 60
        from:
          type: number
        to:
          type: number
        format:
          type: string
          enum:
          - jpg
          - png
          - webp
        width:
          type: integer
          minimum: 16
          maximum: 7680
  responses:
    Error:
      description: Error envelope
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  parameters:
    FormatMd:
      name: format
      in: query
      required: false
      schema:
        type: string
        enum:
        - md
        - markdown
        - srt
        - vtt
      description: 'Render the response in an alternate view instead of JSON. ''md''/''markdown'' returns a Markdown rendering (Content-Type: text/plain), equivalent to sending an Accept: text/plain or text/markdown header. ''srt''/''vtt'' renders the transcript''s timed segments as subtitles (Content-Type: application/x-subrip or text/vtt) — built from the TRANSLATED segments when the translate param was set, otherwise the source transcript''s segments; this is purely an egress view, so it reuses the same cached ExtractResult, cost, and cache key as the plain JSON call. Opt-in only (never inferred from an ambiguous Accept header); JSON stays the default. Extract-family endpoints only (/v1/extract, /v1/metadata, /v1/transcript, /v1/frames); srt/vtt additionally require "transcript" in fields (or "digest", which pulls it in) and return 409 SUBTITLES_UNAVAILABLE if the result has no timed segments (e.g. an older cached entry).'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'API key from POST /v1/keys, sent as ''Authorization: Bearer <key>''.'
x-refined-from:
- openapi.json
- framefetch-net-openapi.json