fypnow

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/videos

Search 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}/analysis

Full 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}/similar

Find videos or slideshows similar to a given one using vector search. Each row carries post_format.

GET /v1/breakouts

List videos currently breaking out among tracked creators. Pass username to see one creator's breakouts.

GET /v1/niches

Browse 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-suggestions

Suggest 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}/videos

Top 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}/hooks

The 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/videos

The 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/hashtags

The 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/hooks

Search 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/detected

Trends 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}/stats

Stats 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/creators

List tracked creators in this workspace, with their ids.

GET /v1/creators/{id}/report

Profile, follower history, winning patterns, posting cadence and hit rate for one creator.

GET /v1/scripts

List generated scripts in this workspace.

GET /v1/scripts/{id}

Fetch one generated script by id.

GET /v1/library

List videos saved to the workspace library.

GET /v1/growth/scorecard

Grade the workspace own account against its niche benchmarks.

GET /v1/usage

Current plan allowances and consumption. Free and unmetered.

Write (14)

POST /v1/analyses

Analyze 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/niches

Create 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}/stop

Stop a Viral Content Agent. Its slot frees at the next UTC midnight and resume_niche reverses it.

POST /v1/niches/{id}/resume

Resume a stopped Viral Content Agent. Needs a free niche slot.

POST /v1/creators

Track 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}/stop

Stop tracking a creator. Their videos are dropped from the catalog (analyses are kept, frozen); resume_tracking_creator reverses it.

POST /v1/creators/{id}/resume

Track a stopped creator again. Videos dropped since the last UTC midnight come back with it.

POST /v1/videos/{video_id}/drop

Drop 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}/undrop

Restore a dropped video to the catalog. Needs a free catalog slot.

POST /v1/trends/search

Search 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/scripts

Generate 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/library

Save 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?
TikTok's own API is built for posting and for Business accounts you own — it will not tell you what is working on someone else's account. FYPNow's API is a research API: it returns AI teardowns of any public TikTok video (hook, scene timing, transcript, retention signals), viral trend search by hashtag, creator breakout detection, and a browsable catalogue of niche-level top performers.
How much does the API cost?
Nothing extra. REST API and MCP access are included on every paid plan with no separate add-on fee. Reads cost nothing beyond the request; the endpoints that reach TikTok or run AI analysis draw down the same quotas the dashboard uses, so there is one bill and one set of limits.
How do I authenticate?
A bearer API key, created in Settings → API and sent as Authorization: Bearer fyp_sk_.... Keys are scoped read or read+write, shown once at creation, and stored only as a SHA-256 hash. OAuth 2.1 is also supported for MCP clients such as Claude. Every credential is bound to exactly one workspace.
Is there an OpenAPI spec?
Yes — a generated OpenAPI 3.1 document at https://api.fypnow.com/openapi.json, suitable for typed client generation. It is produced from the same route table the API dispatches on, so it cannot drift from the implementation. A rendered reference lives at /docs/api.
How does video analysis work over the API?
POST a TikTok URL to /v1/analyses and you get a job handle back immediately, because the analysis runs a video model and takes roughly a minute. Poll the job until it completes, then read the result. The same pattern covers script generation and trend search. Every async response tells you where to poll and how long to wait.
Does the API support YouTube Shorts?
For analysis, yes. POST /v1/analyses accepts YouTube Shorts links (youtube.com/shorts/, youtube.com/watch?v= or youtu.be/) as well as TikTok links and returns the same breakdown a TikTok gets, and niche video lists include Shorts. Creator tracking, breakouts, trend search and the growth scorecard are TikTok-only. See the YouTube Shorts analysis page.
Does the API have webhooks?
Yes, set up in the web app rather than over the API: Settings → Integrations sends breakouts, Viral Content Agent updates, finished analyses and new posts from tracked creators to any HTTPS endpoint as signed JSON (HMAC-SHA256), or straight into Slack or Discord. That works with n8n, Zapier and Make, and it is included on every plan. See the Integrations guide at /docs/integrations.
Can I use it from an AI agent?
That is what it was built for. The same surface is exposed as an MCP server, so Claude and other MCP clients can call it as tools without you writing any HTTP code. See the MCP server page.

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.