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-metadata-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: 3.2.0
info:
title: Framefetch Net Metadata API
version: 1.7.0
contact:
name: FrameFetch
url: https://framefetch.net
termsOfService: https://framefetch.net/impressum
description: 'Operations tagged Metadata 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: Metadata
paths:
/v1/metadata:
post:
operationId: getMetadata
summary: Metadata + insights only
parameters:
- $ref: '#/components/parameters/FormatMd'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/UrlBody'
responses:
'200':
description: Result
content:
application/json:
schema:
$ref: '#/components/schemas/ExtractResult'
tags:
- Metadata
servers:
- url: https://framefetch.net
components:
schemas:
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
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.
UrlBody:
type: object
required:
- url
properties:
url:
type: string
format: uri
description: 'Supported hosts only: youtube.com, youtu.be, tiktok.com, instagram.com, pinterest.*, reddit.com, redd.it'
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