REST API
A TikTok API for research, not posting
TikTok’s own API tells you about accounts you own. This one tells you why someone else’s video worked — the hook, where the scenes cut, what the transcript says, how far it outran its creator’s baseline.
39 endpoints, OpenAPI 3.1, and the same surface again as an MCP server for AI agents. Included on every paid plan.
Analyze a video in one call
curl -X POST https://api.fypnow.com/v1/analyses \
-H "Authorization: Bearer fyp_sk_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://www.tiktok.com/@someone/video/123"}'
# 202 Accepted
{ "data": { "job_id": "...", "status": "processing",
"poll_url": "/v1/analyses/...", "retry_after_seconds": 30 } }Analysis runs a video model, so it returns a job handle rather than blocking. Poll the job, then read the full teardown — hook type and text, scene count and timings, transcript with timestamps, retention signals and virality factors.
39 endpoints, 39 as agent tools
Generated from the API’s own route table. Reads cost nothing beyond the request; writes draw down a plan quota.
Read (25)
GET /v1/analyses/{job_id}Resolves the job handle returned by analyze_tiktok_video into the finished analysis. Status is processing, completed or failed, and the response carries a retry_after_seconds hint for how long to wait between attempts while it is still processing. A failed job also carries a machine-readable error_code (for example rate_limited or limit_reached; null when none was recorded) next to the error text.
GET /v1/scripts/jobs/{job_id}Resolves the job handle returned by generate_script into the finished script. Status is processing, completed or failed, and the response carries a retry_after_seconds hint for how long to wait between attempts while it is still processing.
GET /v1/trends/search/{job_id}Resolves the job handle returned by search_viral_trends into the finished results. Status is processing, completed or failed, and the response carries a retry_after_seconds hint for how long to wait between attempts. A search already in flight is resolved here; starting another for the same hashtag spends a second viral search from the monthly allowance. Off-topic results (judged by the relevance check) are left out by default and counted in hidden_count; pass include_hidden to get them. While the relevance check is still running the status stays processing and relevance_pending is true; poll again until it is false.
GET /v1/videosSearch analyzed videos and slideshows in this workspace by username, view count, date range, or format ('video' or 'slideshow'). Each row carries platform ('tiktok' or 'youtube') and post_format ('photo' carousel, 'slideshow' template, 'video', or null for a video).
GET /v1/videos/{id}/analysisFull AI analysis for one video or slideshow. A video returns hook, timing, scenes and transcript; a slideshow (schema_version carousel_v1) returns cover, slide-by-slide breakdown, narrative, aesthetic, audio, swipe and save drivers, and scores.
GET /v1/videos/{id}/similarFind videos or slideshows similar to a given one using vector search. Each row carries post_format.
GET /v1/breakoutsList videos currently breaking out among tracked creators. Pass username to see one creator's breakouts.
GET /v1/nichesBrowse available niches and their metadata, including catalog_video_count (an approximate count of the videos the niche's catalogue holds, a cached counter updated by the nightly refresh). The workspace's own custom niches come first, then the global catalogue. Each niche has a status: 'active', or 'stopped' (no longer refreshing, but its videos are still there to read). auto_analyse_effective says how its videos get analysed automatically: a global niche ('winners', auto_analyse_shared true) has each refresh's top 10 analysed by fypnow for everyone, free; a custom niche runs 'off', 'winners' or 'all' into this workspace, one catalog slot per video (auto_analyse_mode is the stored choice, null = plan default), and auto_analyse_paused_reason 'catalog_full' means it stopped because the catalog is full (upgrade or free slots). Paginated: when meta.has_more is true, request the next page. Returns niches only, not videos, and carries no per-video AI analysis; that lives behind analyze_tiktok_video. Per-niche numbers (typical views, breakouts, top creators, hashtags) come from get_niche_stats.
GET /v1/niches/keyword-suggestionsSuggest search keywords for a niche idea from what the catalogue already holds: the hashtags that co-occur with the topic (topic, up to 60 characters) in videos from the last 30 days across every niche you can see, ranked by distinct videos, with generic tags such as fyp and viral left out. Each keyword carries videos (how many videos use it) and source: hashtag, or topic when nothing in your niches mentions the topic yet (the topic itself then comes back with videos 0 and a note). matched_global_niche names an existing global niche that already covers the topic, if one does. limit is 1-20 (default 6). Keywords are sized for create_niche (1-3 short phrases). No AI call and no TikTok request is made.
GET /v1/niches/{id}/videosTop videos in one niche, ranked by multiplier: the video's views divided by its creator's follower count (subscribers for YouTube). As an MCP tool it takes the niche's name (e.g. 'forex'; matched case-insensitively on name, then slug, then singular/plural ('protein noodle' finds 'Protein Noodles'), then the niche's keywords, preferring your own niche over a global one) or a niche id from browse_niche_catalog: pass the name directly rather than browsing first. Your stopped niches still answer; meta.niche gives the niche's status ('active' or 'stopped') and last_refreshed_at, so say when a stopped niche last refreshed. Over REST the id is in the path. Returns catalogue stats — views, likes, author, multiplier, platform — not per-video AI analysis. Niches mix TikToks and YouTube Shorts; platform is 'tiktok' or 'youtube'. A hook and scene teardown of a TikTok or a Short comes from analyze_tiktok_video, which takes its video_url. Rows carry no hook data; the top hooks in a niche come from get_niche_hooks. Each row carries post_format; the format input ('video' or 'slideshow') narrows the list to one. Each row also carries content_format (talking_head, voiceover_broll, slideshow, text_on_screen, skit, tutorial, pov, vlog, compilation or other, or null) and content_format_source: 'analysis' when the video has had a full analysis, 'estimated' when it is a guess from the caption, hashtags and cover only (the video itself was not watched). Estimates appear only for formats we have checked; unlabelled videos have null. The content_format input narrows the list to one, within the niche's top 1,000 videos.
GET /v1/niches/{id}/hooksThe top hooks in one niche: hook types from the niche's most viral videos (its top 100 catalogue rows by multiplier) that this workspace has analysed. Takes the niche's name (matched like get_niche_videos) or a niche id. Hooks come from videos this workspace has analysed with analyze_tiktok_video and, for a global niche, from the top videos fypnow analyses for everyone after each refresh (examples carry shared: true); catalogue rows carry no hook data, and other workspaces' analyses are never used. Returns hooks (per hook_type: videos, avg_multiplier, up to 3 examples with hook_text (best first) and up to 3 reusable fill-in templates [{template, count, example_video_id}], ordered by how many top videos use the hook), analysed_count, catalog_considered, and next_to_analyse: the next most viral unanalysed videos (slideshows left out, since their analysis has no hook), each with a ready video_url for analyze_tiktok_video. limit sizes next_to_analyse (default 10, max 25). When few or none are analysed, the answer is to offer analysing next_to_analyse; each analysis costs one catalog slot, and nothing is analysed without the user agreeing. meta.niche gives the niche and its status.
GET /v1/trending/videosThe top breakout videos across every niche you can see (the global catalogue plus your own niches) that entered the catalogue in the last N hours (hours, 6-168, default 48). Optional niche (id or name) narrows it to one niche, platform to 'tiktok' or 'youtube'. Ranked by multiplier (views / followers) by default, or order_by 'weighted' for ln(views / followers) x ln(followers), which favours big wins on larger accounts. Each row carries the niche, author, a ready url for analyze_tiktok_video, views, followers, multiplier, weighted_score, posted_at and first_seen_at. limit is 1-50 (default 20); the list is not paged. An empty window returns an empty list with meta.hours and meta.since. Catalogue stats only, not per-video analysis.
GET /v1/trending/hashtagsThe hashtags gaining the most ground across every niche you can see (the global catalogue plus your own niches). Compares the distinct creators posting videos that entered the catalogue in the last N days (days, 1-30, default 7) with the N days before: each tag carries creators, prev_creators, growth ((creators - prev_creators) / max(prev_creators, 1)), videos, prev_videos, median_multiplier and top_video_id. Tags used by fewer than 3 creators in the window are left out, as are generic platform tags such as fyp and viral. Optional niche (id or name) narrows it to one niche. limit is 1-50 (default 20); the list is not paged. Catalogue stats only, not per-video analysis.
GET /v1/hashtags/{tag}One hashtag in the catalogue (a leading # and capital letters are ignored): a daily series of how many videos used it and their median multiplier over the last N days (days, 7-90, default 30), total_videos, and the top 5 videos with a ready url for analyze_tiktok_video. Optional niche (id or name) narrows it to one niche. A tag with no videos returns an empty series, not an error. Catalogue stats only, not per-video analysis.
GET /v1/hooksSearch the hooks of analysed videos across every niche you can see (the global catalogue plus your own niches): your own analyses and fypnow's shared ones, best multiplier first. Optional query is a case-insensitive text match on the hook (up to 80 characters), hook_type one of question, bold_claim, curiosity_gap, shock, relatable, tutorial_promise, story_opener or visual_spectacle, niche (id or name) narrows it to one niche. Each row has the hook text, a reusable fill-in hook_template (null for older analyses), the niche, author, a ready url for analyze_tiktok_video, views and multiplier. limit is 1-50 (default 20); the list is not paged. Videos nobody has analysed yet are not searched.
GET /v1/trends/detectedTrends several creators are posting about right now, across every niche you can see (the global catalogue plus your own niches): a news event, a release, a match or a challenge, detected daily from the catalogue. Each trend has a status (new, rising, peaking, fading or ended) and status_since, the niche, videos, creators, best_multiplier (views / followers), first_seen and last_seen (dates of its first and latest video), detected_at, a daily series (videos and new creators per day, with that day's status), 3 to 6 example videos with a ready url for analyze_tiktok_video, suggested keywords for a niche agent, its most shared hashtag, and also_in (other niches with the same videos). Optional niche (id or name), status (comma list or open, default open: new, rising, peaking and fading) and days (1-60, default 14). limit is 1-50 (default 20; a value outside that range is clamped to it, not rejected); the list is not paged. meta carries as_of (the date of the latest daily check) and backfill_complete. Trend names are generated from captions. Catalogue stats only, not per-video analysis.
GET /v1/trends/detected/{id}One trend from get_trends by id, with the same fields plus members: every visible video in it (up to 50, best multiplier first, each with a ready url for analyze_tiktok_video). The multiplier is views / followers. An unknown id, or a trend outside the niches you can see, is a 404.
GET /v1/niches/{id}/statsStats for one niche from its nightly snapshot: typical post views, breakout posts (3x or more the creator's followers), active creators and views on this week's top posts, each next to the snapshot from a week earlier; top and rising creators, sounds in use, top hashtags, posting times, the top 3 posts this week, posts and breakouts per posting day, and the daily snapshot series. Takes a niche id from browse_niche_catalog. The numbers describe the top posts the nightly crawl keeps per niche (about 50 a night, about 100 for custom niches), not all of TikTok. latest is null until the first nightly snapshot, and week-over-week comparisons need a week of snapshots. format_mix counts the niche's videos posted in the window by content_format [{content_format, breakouts, all, source}] (breakouts = 3x or more the creator's followers), with source 'analysis', 'estimated' (a caption-and-cover guess, shown only for formats we have checked) or 'mixed'; format_mix_unlabelled counts videos with no usable format.
GET /v1/creatorsList tracked creators in this workspace, with their ids.
GET /v1/creators/{id}/reportProfile, follower history, winning patterns, posting cadence and hit rate for one creator.
GET /v1/scriptsList generated scripts in this workspace.
GET /v1/scripts/{id}Fetch one generated script by id.
GET /v1/libraryList videos saved to the workspace library.
GET /v1/growth/scorecardGrade the workspace own account against its niche benchmarks.
GET /v1/usageCurrent plan allowances and consumption. Free and unmetered.
Write (14)
POST /v1/analysesAnalyze a TikTok video or photo slideshow (/video/ or /photo/ links) or a YouTube Short (youtube.com/shorts/, youtube.com/watch?v= or youtu.be/ links) by URL. Consumes one catalog slot.
POST /v1/nichesCreate a Viral Content Agent that watches a niche by keyword.
PATCH /v1/niches/{id}Rename a Viral Content Agent, change its 1-3 keywords, and/or set auto_analyse_mode: 'off', 'winners' (each refresh's top 10 by multiplier) or 'all' (every new video), or 'default' for the plan default (off on Creator, all on other plans). Changed keywords re-seed the niche. Auto-analysis uses one catalog slot per video, highest multiplier first, and stops when the catalog is full.
POST /v1/niches/{id}/stopStop a Viral Content Agent. Its slot frees at the next UTC midnight and resume_niche reverses it.
POST /v1/niches/{id}/resumeResume a stopped Viral Content Agent. Needs a free niche slot.
POST /v1/creatorsTrack a TikTok creator by username or profile URL (TikTok only: YouTube channels are not supported yet; analyse Shorts one at a time). Adds the creator to the workspace and scrapes their latest videos in the background; returns a job handle (202). A creator already tracked returns already_tracked, a stopped one is reported as creator_stopped.
POST /v1/creators/{id}/stopStop tracking a creator. Their videos are dropped from the catalog (analyses are kept, frozen); resume_tracking_creator reverses it.
POST /v1/creators/{id}/resumeTrack a stopped creator again. Videos dropped since the last UTC midnight come back with it.
POST /v1/videos/{video_id}/dropDrop a video from the catalog. The analysis is kept, frozen, and the catalog slot frees at the next UTC midnight.
POST /v1/videos/{video_id}/undropRestore a dropped video to the catalog. Needs a free catalog slot.
POST /v1/trends/searchSearch for breakout videos by hashtag. A cached hashtag returns full results right away. An uncached one returns a job handle (202) with no results yet; that handle is resolved by get_trend_search_result, which reports status processing, completed or failed and carries the results. A cached hashtag whose relevance check is still running also returns a job handle (202) too, so it is polled rather than searched again. Off-topic results (judged by the relevance check) are left out by default and counted in hidden_count; pass include_hidden to get them.
POST /v1/scriptsGenerate a script grounded in the workspace top performers. Returns a job handle (202) rather than the script itself, because generation takes up to a minute. The handle is resolved by get_script_result, which reports status completed or failed and carries the script.
POST /v1/librarySave a video to the workspace library. Works for TikToks and YouTube Shorts; pass platform ('tiktok' or 'youtube') from get_niche_videos, or omit it and a YouTube-shaped id is saved as a Short.
DELETE /v1/library/{video_id}Remove a video from the library.
Built to be integrated against
One response shape
Every endpoint returns {"data": …} or {"error": {"code", "message"}}. `message` is always a string — never a string-or-array union that forces defensive parsing.
Machine-readable error codes
Branch on `code`, not on prose. catalog_full, write_scope_required, rate_limit_exceeded, api_access_required — each means one thing.
Honest coverage
Responses report what is missing rather than nulling it silently. If a transcript could not be extracted, the payload says so.
Generated spec
The OpenAPI document and the docs are generated from the route table the API dispatches on, so they cannot describe an endpoint that does not exist.
Async where it matters
Anything that runs a model or reaches TikTok returns a job handle with a poll URL and a realistic retry interval.
One workspace per credential
No request parameter can reach a second workspace. Entitlement is re-checked on every request, not at key creation.
Questions
Is there a TikTok analytics API?
How much does the API cost?
How do I authenticate?
Is there an OpenAPI spec?
How does video analysis work over the API?
Does the API support YouTube Shorts?
Does the API have webhooks?
Can I use it from an AI agent?
No API add-on, no separate bill
Every paid plan includes the REST API and the MCP server, against the same quotas you already have.