Hook Detector
Real TikTok and Instagram hooks that already work, in any language, with why each travelled.
| Endpoint | https://api.hookdetector.com/mcp (streamable-http) |
|---|---|
| Registry version | 2.4.0 |
| Now | 154 tools · grade D (55) · pin ts_a2e91d629d465c27bea2b180b689d00a · protocol 2025-06-18 |
| First / last listed | 2026-10-28 03:59 UTC / 2026-10-28 03:59 UTC |
| Grade over time | 2026-10-28: D (55), 154 tools |
Is this your server? Own a server? ToolFit hosted watch re-checks it every 24 h ($0.25 per 30 days) or 6 h ($0.60) and sends you an HMAC-signed webhook when its tools or grade change: POST https://api.youraitools.co/toolfit/v1/watch. To opt out, see About & opt-out.
Tools: create_account showcase find_hooks get_run list_runs find_long_hooks find_packaging save_preset list_presets delete_preset write_titles write_ideas get_call list_calls find_similar search_thumbnails score_package preview_package make_thumbnails get_thumbnails edit_thumbnail recreate_thumbnail optimize_video get_optimize ab_set get_find keep_find clear_find_decision list_finds remix_find list_remixes get_remix list_kept_finds export_run get_hook embed_hook keep_hook clear_decision remix_hook list_keeps balance delete_account chat list_conversations get_conversation usage list_keys create_key revoke_key request_access list_access_requests approve_access_request reject_access_request list_access_codes create_access_code revoke_access_code admin_overview admin_list_accounts admin_adjust_credits admin_list_runs admin_list_actions list_strategies create_folder list_folders get_folder rename_folder delete_folder save_to_folder edit_folder_item remove_from_folder share_folder unshare_folder get_shared_folder swipe_file share_run start_job list_jobs get_job search_index random_outliers get_channel channel_outliers similar_channels search_channels niche_report list_niches video_stats list_winners create_tracker list_trackers get_tracker update_tracker delete_tracker add_to_tracker remove_from_tracker tracker_feed clone_tracker tracker_alerts create_alert list_alerts get_alert update_alert delete_alert run_alert create_webhook list_webhooks delete_webhook test_webhook webhook_deliveries video_scorecard list_trends list_formats format_videos daily_ideas create_agent list_agents get_agent update_agent delete_agent get_skeleton review_video read_retention_graph review_hook write_hook write_script review_script review_edit write_upload_pack clean_recording trending_shorts review_short research_keywords comment_insights find_sponsors get_team create_team move_team_credits invite_to_team revoke_team_invite view_team_invite accept_team_invite remove_team_member set_team_member_cap thumbnail_attention create_poll list_polls get_poll delete_poll next_poll vote_poll close_poll video_badges list_research get_research
create_account | Create an account and get an API key with free credits. Needs a beta access code
(access_code, HD-XXXX-XXXX; case and dashes do not matter): without one the error is
403 access_code_required, and a code that does not work is 403 invalid_access_code.
Ask for a code with request_access, or at hookdetector.com/access. No key needed for
this call. label is an optional note up to 120 ch params: access_code, label |
showcase | Real hooks this service has delivered, for a wait screen: talking heads only, each
hook_id, still_url (a JPEG, no key needed), platform, creator, views and line (the
banner on the video, else its opening line). The most viewed first, one per creator,
only what is already public on TikTok or Instagram: never a topic, an account or a run.
No key needed. Cached 10 minutes. Free. REST: params: n |
find_hooks | Start hook research on a topic across TikTok, Instagram and YouTube Shorts (Shorts
only, never long-form YouTube; platform "youtube"). platforms (since 2026-10-10, any of
"tiktok", "instagram", "youtube"; all three when left out) searches and delivers only
those: ["instagram"] is Instagram reels only.
What it does: searches both platforms, reads what each clip says and shows, and
params: topic*, count, conversation_id, reuse, wait_seconds, idempotency_key, api_key, language, country, posted_within_days, seed_hook_ids, platforms |
get_run | A research run: its status, progress, charge and every hook it produced.
wait_seconds 0 to 50: wait up to that long for the run to finish, returning the
moment it is done or failed. Use wait_seconds=50 and call again while status is
"queued" or "running"; a fresh run needs about 3 or 4 such calls. progress has
stage, message and updated_at, plus counts once the research reports th params: run_id*, wait_seconds, api_key, since |
list_runs | Your research runs, newest first, without their results, limit 1 to 100 (default 20)
per page. Each run says its kind: "short" (find_hooks), "long" (find_long_hooks) or
"packaging" (find_packaging); pass kind to list only one. Returns {"runs": [...],
"next_cursor"}: pass next_cursor back as cursor for the next page; it is null on the
last. Same shape as GET /v1/runs. Next step: ope params: limit, cursor, api_key, kind |
find_long_hooks | Find long-form hooks: how the YouTube videos that beat their own channel open, on a
topic. Long-form YouTube only, never Shorts, TikTok or Instagram (for those: find_hooks).
What it does: searches YouTube for long-form videos on the topic, keeps only the
outliers (a video whose views are at least min_outlier times the median views of its
own channel's recent uploads; 2 by default) params: topic*, count, language, country, min_outlier, posted_within_days, channel_size, intro_seconds, openers, reuse, wait_seconds, idempotency_key, filters, preset_id, api_key |
find_packaging | Find packaging: the titles and thumbnails that earned the click on a topic, from
long-form YouTube videos that beat their own channel.
What it does: runs the same outlier search as find_long_hooks (long-form YouTube,
2023 or later, views at least min_outlier times the channel's usual), then looks at
each video's thumbnail beside its title and says what the pair is doing.
What params: topic*, count, language, country, min_outlier, posted_within_days, channel_size, ideas, reuse, wait_seconds, idempotency_key, content_type, filters, preset_id, api_key |
save_preset | Save filters under a name for one tab: "long", "packaging" or "library" (the bounds
are those of find_packaging's filters; a library preset may also hold min_comments,
max_comments, posted_within_days and language). The same name on the same tab replaces
it. Start a run from it with preset_id on find_long_hooks or find_packaging. At most 50
an account. Same as POST /v1/presets. Fre params: name*, tab*, filters, api_key |
list_presets | Your saved filter presets, the newest change first; tab ("long", "packaging",
"library") narrows. Same as GET /v1/presets. Free. params: tab, api_key |
delete_preset | Delete one of your presets. Same as DELETE /v1/presets/{preset_id}. Free. Errors:
404 preset_not_found. params: preset_id*, api_key |
write_titles | Write 20 to 40 titles for your video, each borrowing the device and structure of one
real outlier (a video that beat its own channel): the finds of one of your runs, or the
shared index's videos nearest your topic by meaning. Each title: title, chars, first_40
(what a phone feed surely shows), device, borrows, and from (the real outlier: video_id,
title, channel, multiple, find_id) params: topic, run_id, count, channel, content_type, idempotency_key, api_key |
write_ideas | Write ideas for new videos: each a title, a thumbnail concept (one visible action)
and the words to print, built on one to three real outliers (based_on, each with its
video_id, title, multiple, find_id and bend niche when it came from another niche).
constraints are rules every idea keeps (said in fits). band (10x, 5x, 2x) is the median
multiple of the finds behind the idea, never params: topic, run_id, count, constraints, content_type, idempotency_key, api_key |
get_call | One call of a priced tool (titles and the tools after it): tool, credits, charged,
status (pending, done, failed), request and result. Same as GET /v1/calls/{call_id}.
Free. Errors: 404 call_not_found. params: call_id*, api_key |
list_calls | Your calls of priced tools, newest first; tool ("titles", ...) narrows. Same as GET
/v1/calls. Free. params: tool, limit, api_key |
find_similar | The videos in the shared index nearest one of your finds (find_id from a Packaging or
Long form run), nearest first, never the find's own video. Each has distance (0 is the
same; measures says how it is computed), its numbers and its multiple over its
channel's median. A find not indexed yet is matched by its own words (matched_from).
Free. Same as GET /v1/finds/{find_id}/similar. params: find_id*, type, limit, min_multiple, content_type, posted_within_days, api_key |
search_thumbnails | Thumbnails in the shared index by what the picture shows (q), or like a picture
(image_url: read once by the model as subject, action, words and setting, then
searched). Each result has matched_by (text or meaning). Free; image reads at most 60
an hour. Same as GET /v1/index/thumbnails and POST /v1/index/thumbnails/by-image. params: q, image_url, limit, min_multiple, content_type, api_key |
score_package | Score a package against the real outliers on its subject, part by part (title device,
length, words on the picture, faces, the words' role, contrast, brightness): each part
says how many outliers it matches; pattern_match (0 to 100) is the mean share: how much
the package resembles the subject's outliers, never a click-through rate or a prediction
(in our test it scored outliers ab params: title, thumbnail, video_url, run_id, topic, content_type, idempotency_key, api_key |
preview_package | Your package in a mock YouTube feed among a run's winners: view home, search, sidebar,
phone (marks where a phone cuts the title) or tv; theme dark or light; look normal, grey
or blur. Returns png_base64 and mine_at. Free. Same as POST /v1/packaging/preview. params: title*, thumbnail, run_id, topic, view, theme, look, seed, api_key |
make_thumbnails | Make 2 to 12 thumbnails (default 4): 3 different concepts first, then images (Nano
Banana 2.1, 1K or 4K), every printed word read back and checked letter by letter, a face
only from your photos or your channel's own thumbnails. Answers at once with call_id and
status pending; read it with get_thumbnails until done. 4 credits a delivered 1K image, 12
a 4K one, charged only for what params: title*, concept, words, mode, faces, channel, reference, sketch, background, count, size, run_id, topic, idempotency_key, api_key |
get_thumbnails | A thumbnails call: status, concepts and every image so far (url signed for 7 days,
width, height, words, words_checked, cost_usd). Same as GET /v1/thumbnails/{call_id}. Free. params: call_id*, api_key |
edit_thumbnail | Edit one thumbnail (an image of your thumbnails call, or a picture you send): op erase,
edit, face_swap, text, text_variations, upscale, fix, crop or color. crop and color are
free; upscale 12; the rest 4 (a version each for text_variations), charged only for what
is delivered. Answers at once; read it with get_thumbnails. Same as POST /v1/thumbnails/edit. params: op*, source, source_call_id, source_n, region, prompt, faces, words, variations, fixes, score_call_id, brightness, contrast, saturation, idempotency_key, api_key |
recreate_thumbnail | New thumbnails for your video with a YouTube video's own thumbnail as the layout
reference (2 to 4 images, every printed word checked); priced as make_thumbnails. Same as
POST /v1/thumbnails/recreate; read it with get_thumbnails. params: video_url*, title, words, count, size, mode, idempotency_key, api_key |
optimize_video | New packages (4, 8 or 12) for your published video: the original scored first against
the real outliers on its subject, then each new package (title, thumbnail with every word
checked, what it tests) scored the same way, best first, with vs_original. 10 credits a
delivered package. Answers at once; read it with get_optimize. Same as POST /v1/optimize. params: video_url*, count, run_id, size, idempotency_key, api_key |
get_optimize | An Optimize call: the original's score and every new package so far. Same as GET
/v1/optimize/{call_id}. Free. params: call_id*, api_key |
ab_set | Pack 2 or 3 images of one of your thumbnails, edit or Optimize calls for YouTube
Studio's Test and Compare: a zip of A, B, C (1280x720, under 2 MB) and a note of what each
tests. Free. Same as POST /v1/ab. params: source_call_id*, picks*, api_key |
get_find | One result of a long or packaging run with every field: the video, its numbers and
the opening or the package analysis. find_id comes from a run's finds (get_run) or from
list_kept_finds. Same shape as GET /v1/finds/{find_id}. Free. Errors: 404
find_not_found, 422 for an id that is not a UUID. params: find_id*, api_key |
keep_find | Keep or reject a find (a long-form hook or a package): verdict is "keep" (default)
or "reject", and the last verdict wins. The verdict is the video's on that tab: every
find of the same video you have there carries it, so a later run that finds the video
again shows it already kept. Kept videos come back from list_kept_finds, across all
runs. Returns {"find_id", "verdict"}. Same as params: find_id*, verdict, api_key |
clear_find_decision | Undo keep_find: the video goes back to having no verdict, on every find of it, and
leaves list_kept_finds.
Returns {"find_id", "verdict": null}. Clearing a find with no decision is the same
success, so a retry is safe. Same as DELETE /v1/finds/{find_id}/decision. Free. params: find_id*, api_key |
list_finds | The index: every video your long and packaging runs found, across all runs, one
entry a video on each tab (its newest read, with the keep or reject made on the
video). Each is a full find object: the title and thumbnail_url as YouTube shows them,
views, channel_median_views, outlier (views over the channel's usual) and
outlier_score (0 to 100 on one fixed scale, so entries from dif params: kind, q, sort, tier, min_score, device, min_multiple, max_multiple, min_views, max_views, min_channel_median, max_channel_median, min_comments, max_comments, min_duration_s, max_duration_s, posted_within_days, language, limit, cursor, api_key |
remix_find | Make it mine, for a long-form opening or a package: write up to n (1 to 5, default
3) new ones for your niche that keep one real find's structure. From a long find,
`written` holds openings: hook (what the creator says first), then (what the next half
minute has to deliver) and kept_structure, built on the find's template and its order
of beats. From a packaging find it holds packa params: find_id, niche, n, mode, video_brief, idempotency_key, api_key |
list_remixes | The remixes you paid for from one hook (hook_id) or one find (find_id), newest
first, each as its answer held it, with remix_id and created_at. Returns {"remixes":
[...]}. Free. 404 hook_not_found or find_not_found for one that is not yours. Same as
GET /v1/hooks/{hook_id}/remixes and GET /v1/finds/{find_id}/remixes. params: hook_id, find_id, api_key |
get_remix | One remix you paid for (from remix_hook, remix_find or a chat turn), as its answer
held it. Free. 404 remix_not_found for one that is not yours. Same as GET
/v1/remixes/{remix_id}. params: remix_id*, api_key |
list_kept_finds | The videos you kept with keep_find (long-form hooks and packages), newest decision
first: one entry a video on each tab across all runs, or the kept finds of one run_id,
limit 1 to 100 (default 100) per page.
Returns {"kept": [...], "count": n on this page, "next_cursor"} with full find objects.
Same shape as GET /v1/finds/keeps. Free. Errors: 422 for a bad kind, run_id or cursor. params: kind, run_id, limit, cursor, api_key |
export_run | A finished run's hooks as a file a creator can open: format "csv" (default; one row
per hook, opens in any spreadsheet, formula-like cells defused with a leading quote),
"json" (the full hook objects) or "md" (Markdown notes, one section per hook).
Returns {"filename", "content_type", "format", "content"}, where content is the whole
file as text: write it to filename. The same byt params: run_id*, format, api_key |
get_hook | One hook with every field: its opening line, transcript, watch_url and the
vertical player_url (null only for an unusable id or a photo post found before
2026-09-26; runs deliver single videos only). hook_id comes from get_run. Free. params: hook_id*, api_key |
embed_hook | Official TikTok or Instagram embed HTML for a hook, so the clip plays inside your
own page. kind is "embed", or "fallback" when the creator disabled embedding or the
clip is a photo post found before 2026-09-26 (then show thumbnail, which falls back to
the hook's still_url, and the transcript). For a plain vertical iframe use the hook's
player_url instead. Free. params: hook_id*, api_key |
keep_hook | Keep or reject a hook: verdict is "keep" (default) or "reject", and the last
verdict wins. A reject may say why: reason is off_subject, weak_opening, wrong_language,
low_quality, already_have or other, and note (up to 280 characters) your own words.
Kept hooks come back from list_keeps, across all runs. Free. params: hook_id*, verdict, reason, note, api_key |
clear_decision | Undo keep_hook: the hook goes back to having no verdict, so it leaves list_keeps and
its export row carries none. Returns {"hook_id", "verdict": null}. Clearing a hook with
no decision is the same success, so a retry is safe. Same as DELETE
/v1/hooks/{hook_id}/decision. Free. Errors: 404 hook_not_found, 422 for an id that is
not a UUID. params: hook_id*, api_key |
remix_hook | Make it mine: write up to n new opening lines (1 to 5, default 3) for your niche
that keep a real hook's structure, the device that made it travel, with the subject
swapped for yours. hook_id is one of your hooks (from get_run, get_hook or
list_keeps); 404 hook_not_found otherwise. Leave mode out: "intro" (Write my intro) is
remix_find on a long-form find, and is 422 here, before a params: hook_id, niche, n, mode, idempotency_key, api_key |
list_keeps | The hooks you kept with keep_hook, newest decision first, across all runs or within
one run_id, limit 1 to 100 (default 100) per page. Returns {"kept": [...], "count": n
on this page, "next_cursor"} with full hook objects; pass next_cursor back as cursor
for more. Same shape as GET /v1/keeps. Free. Errors: 422 for a bad run_id or cursor. params: run_id, limit, cursor, api_key |
balance | Your account and remaining credits right now: account_id, credits, key_prefix and
key_id of the key making this call, label, created_at, and that key's scopes,
credit_limit and expires_at, and user (the person signed in with Google, or null).
Same shape as GET /v1/me. A
run needs at least 40 credits and reserves up to 200. For spend, credits held by
in-flight runs and daily his params: api_key |
delete_account | Erase your account and everything in it, for good: every API key, run, hook, keep
or reject decision, conversation and message. Unspent credits go with it. It cannot
be undone.
confirm must be exactly "delete my account", or nothing happens (422
confirmation_required). Refused with 409 run_in_flight while a run is queued or
running: wait for it with get_run first. Returns {"de params: confirm, api_key |
chat | One conversational turn, for an agent relaying a person's words. It either asks
ONE clarifying question (action "clarify"), answers about delivered hooks or the tool
(action "answer", run null, no credits), or starts a research run (action
"research", with the started run under "run"), exactly like POST /v1/chat.
Every response has suggestions: 0 to 4 follow-ups, [] for research.
params: message*, conversation_id, api_key, language, country, idempotency_key, posted_within_days, seed_hook_ids, count, platforms |
list_conversations | Your chat conversations, most recently active first, limit 1 to 100 (default 30)
per page: conversation_id, title, created_at, updated_at, language, country and
messages (the count). Nullable language/country are the saved search picker settings.
Returns {"conversations": [...], "next_cursor"}; pass next_cursor back as cursor for
more. Same shape as GET /v1/conversations. Next step params: limit, cursor, api_key |
get_conversation | One chat conversation: its newest messages in order (role, content, run_id,
created_at), a page of `limit`, with earlier_cursor for the older ones (null when the
page reaches the first message), and the runs those messages hold, with their hooks,
plus nullable language and country search picker settings. Same shape as GET
/v1/conversations/{conversation_id}. Free. Errors: 404 conve params: conversation_id*, limit, before, api_key |
usage | Your credits and what you have spent: credits (balance now), spent_total,
reserved_now (credits held by runs still in flight, refunded in part when they
finish), runs_total, last_30_days (one entry per UTC day: date, runs, charged) and
recent (your 20 newest runs). Same shape as GET /v1/usage. Free. params: api_key |
list_keys | Your API keys and what each may do. keys: key_id, name, prefix, created_at,
last_used_at and current (true for the key making this call). access, per key_id:
scopes, credit_limit, credits_used, expires_at and expired. scopes: the calling key's.
The original signup key has key_id "original". The keys themselves are never shown
again. Needs admin. Same shape as GET /v1/keys. Free. params: api_key |
create_key | Create another API key on your account, for example one per agent or machine, so
you can revoke one without touching the others. name is up to 60 characters.
Give the key only what it needs. scopes: any of "read" (read runs, hooks, keeps,
usage), "write" (keep, reject, undo, chat), "research" (start runs, which spend
credits), "admin" (manage keys, delete the account); all four wh params: name, scopes, credit_limit, expires_in_days, api_key |
revoke_key | Revoke one of your API keys at once: key_id from list_keys, or "original" for the
signup key. Any key may revoke itself (the result says so, and that key stops working
immediately); revoking another needs admin. Never the last active key on the account
(409): create another with create_key first.
If a key leaked, pass key_id "others": every key of the account except the one you
params: key_id*, api_key |
request_access | Ask for the beta access code a new account needs (create_account's access_code).
email is where the code is sent; note is optional (who you are, up to 500
characters). The owner approves the request and the code is emailed at once; it works
once, in any agent or on the web. Returns status pending (waiting for approval) or
emailed (sent now). No key needed. Limited to 5 per address params: email*, note |
list_access_requests | Owner only: every access request, newest first, optionally only one status
(pending, approved, rejected). Each has request_id, email, note, status, code_id,
code_prefix, created_at and decided_at. Never a code. Needs the admin scope and an
admin account (403 admin_required otherwise). Free. params: status, api_key |
approve_access_request | Owner only: approve an access request. Makes a one-use code, marks the request
approved and emails the code. The code is in this result once, with emailed true or
false; when false, send it yourself or approve again (the unused code is revoked and
a new one sent). 409 request_already_decided once its code was used. Free. params: request_id, api_key |
reject_access_request | Owner only: reject a pending access request. Nothing is emailed. An approved or
rejected request is 409 request_already_decided. Free. params: request_id, api_key |
list_access_codes | Owner only: every access code, newest first, with code_id, code_prefix, email,
note, source, max_uses, uses, expires_at, revoked_at, created_at and usable. Never the
code itself. Free. params: api_key |
create_access_code | Owner only: make an access code to hand out. max_uses 1 to 100000 (default 1),
expires_in_days 1 to 365 (optional), note your own. email binds it to one person: then
only Google sign-in with that verified email redeems it, never the API or MCP; leave
it out for a code that works on every door. The code is in this result only. Free. params: email, note, max_uses, expires_in_days, api_key |
revoke_access_code | Owner only: revoke an access code (code_id from list_access_codes). It admits
nobody from now on; accounts it already made keep working. 404 access_code_not_found
for an unknown id. Free. params: code_id, api_key |
admin_overview | Owner only: the whole service at a glance, as GET /v1/admin/overview. Counts of
accounts and people; runs (total, last_24h, last_7d, failed_24h, in_flight); hooks;
credits (charged_24h, charged_7d, charged_total, balance_total); access
(pending_requests, active_codes, redemptions); search (credits_left, low,
accepting_runs; null when not read yet); and the running commit. Needs the params: api_key |
admin_list_accounts | Owner only: every account, newest first, as GET /v1/admin/accounts: {total,
accounts: [{id, email, name, label, credits, created_at, last_seen_at, runs, hooks,
charged_total, is_admin, admitted_by, keys_active}]}. Free. params: q, limit, offset, api_key |
admin_adjust_credits | Owner only: add or remove an account's credits, as POST
/v1/admin/accounts/{account_id}/credits. A change that would take the balance below
zero is 422 credits_below_zero and nothing changes; an unknown account is 404
account_not_found. Every change is audited (admin_list_actions). Returns {account_id,
credits, delta}. params: account_id, delta, note, api_key |
admin_list_runs | Owner only: every account's research runs, newest first, as GET /v1/admin/runs:
{runs: [{run_id, account_id, email, topic, language, country, status, requested,
hooks, reserved, charged, failure_kind, error, created_at, finished_at}]}. Free. params: limit, status, account_id, api_key |
admin_list_actions | Owner only: the audit of password sign-ins and credit changes, newest first, as GET
/v1/admin/actions: {actions: [{id, action, actor_email, target_account_id, detail,
created_at}]}. Free. params: limit, api_key |
list_strategies | The hook strategy library: every kind of long-form hook the shared index holds at least
3 openings of, with its plain name, count, the median multiple of those videos over their
channels' usual views, the median hook length in seconds, the template most share, and up
to 3 real examples (title, hook as said, video_id, channel, multiple). Counted from the
index, never by a model; pub params: q, api_key |
create_folder | Make a named folder on one tab to file hooks or finds in. The same name again on
that tab (case and spaces aside) returns the folder already there with created false,
so a retry never makes two. At most 200 folders an account (409
folder_limit_reached). Returns the folder: folder_id, kind, name, item_count, cover,
shared, share_url, created. Same as POST /v1/folders. Free. Next: sa params: name, kind, description, team, api_key |
list_folders | Your folders, the most recently changed first, each with item_count, up to 4 cover
thumbnails and its share link when shared. With hook_id or find_id, each folder also
has contains: the item id when it holds that video (any run's copy), else null.
Returns {"folders": [...], "count"}. Same as GET /v1/folders. Free. params: kind, hook_id, find_id, api_key |
get_folder | One of your folders and its items, newest filed first, limit 1 to 100 a page (page
with next_cursor). Each item has item_id, note, thumbnail_url, title and the full hook
or find object. Same as GET /v1/folders/{folder_id}. Free. Errors: 404
folder_not_found. params: folder_id, limit, cursor, api_key |
rename_folder | Rename a folder, change its description, or both. A name another folder on the tab
already has is 409 folder_exists. Returns the folder. Same as PATCH
/v1/folders/{folder_id}. Free. params: folder_id, name, description, api_key |
delete_folder | Delete a folder, its items and its share link at once (the link stops working). The
hooks and finds in it, and their keeps, stay. Returns {"folder_id", "deleted": true}.
Same as DELETE /v1/folders/{folder_id}. Free. Errors: 404 folder_not_found. params: folder_id, api_key |
save_to_folder | File one video in a folder of its tab: a find (find_id) or any public YouTube video
(video_id) in a long or packaging folder, a hook (hook_id) in a short one, with an
optional note. A video already in the
folder (the same find, another run's find of it, the same hook) returns that item with
created false; a note given then replaces its note. Filing does not keep it. Same as
POS params: folder_id, find_id, hook_id, note, video_id, api_key |
edit_folder_item | Set the note on one item of a folder. Returns the item. Same as PATCH
/v1/folders/{folder_id}/items/{item_id}. Free. Errors: 404 item_not_found. params: folder_id, item_id, note, api_key |
remove_from_folder | Take one video out of a folder; the hook or find and its keep stay. Returns
{"item_id", "removed": true}. Same as DELETE /v1/folders/{folder_id}/items/{item_id}.
Free. Errors: 404 item_not_found (also on a second remove). params: folder_id, item_id, api_key |
share_folder | Turn on a folder's share link: share_url is a public read-only page anyone with it
opens signed out (hookdetector.com/f/<token>); api_url is the same as JSON
(get_shared_folder). It shows the folder's name, description and items with their
notes, never anything about the account. A shared folder keeps its link. Same as
POST /v1/folders/{folder_id}/share. Free. params: folder_id, api_key |
unshare_folder | Turn a folder's share link off: the old link stops working at once; share_folder
again makes a new one. Same as DELETE /v1/folders/{folder_id}/share. Free. params: folder_id, api_key |
get_shared_folder | A shared folder as anyone with its link sees it: name, description, kind,
item_count and items (public fields and the owner's note), newest first, paged. No key
needed; limited per address (429). A link never made or turned off is 404
shared_folder_not_found. Same as GET /v1/shared/folders/{token}. Free. params: token, limit, cursor |
swipe_file | Your swipe file: the title structures of the Packaging finds you kept or filed, each
title_template with its title_device, count (how many of those videos use it, one a
video) and best (the example with the highest outlier_score, 0 to 100). The most used
first; packages is how many videos were read, skipped how many had no structure. Same
as GET /v1/swipe. Free. params: api_key |
share_run | Share a finished Short form run as a public, read-only page anyone can open with the
link, no sign-in: each hook's spoken line, on-screen words, idea, plays, creator and its
video, in the Hook Detector skill page layout. Nothing about the account is on it.
Returns {"run_id", "token", "url"}; give the person the url
(https://hookdetector.com/p/<token>). Idempotent: a run keeps one params: run_id, api_key |
start_job | Start a background job on Hook Detector's job runner. Only echo can be started by
hand: it waits `seconds` and answers `message` back with how many attempts it took (a
job survives a deploy). At most 3 an hour per account. Free. Same as POST /v1/jobs;
read it back with get_job. params: kind, seconds, message, api_key |
list_jobs | This account's background jobs, newest first (tracker refreshes, alerts, reviews,
echo): status, attempts, credits, result or error. Free. Same as GET /v1/jobs. params: limit, api_key |
get_job | One background job of this account. Same as GET /v1/jobs/{job_id}. Errors: 404
job_not_found for another account's job or an unknown id. params: job_id*, api_key |
search_index | Search the shared index of public YouTube videos Hook Detector's runs measured, with
no run: words by text and meaning, or browse; filters for the multiple, views, long or
short, recency, channel size and language. Free. Same as GET /v1/index/search. params: q, sort, limit, cursor, min_multiple, max_multiple, min_views, max_views, content_type, posted_within_days, channel_size, language, api_key |
random_outliers | Outliers at random from the shared index (5x their channel's usual and over by
default), a different set each call. Free. Same as GET /v1/index/random. params: limit, min_multiple, max_multiple, min_views, max_views, content_type, posted_within_days, channel_size, language, api_key |
get_channel | A channel page: subscribers and totals, every recent long upload scored against the
channel itself (outliers at 2x its median and over), and its momentum. Free. Same as
GET /v1/channels/{ref}. params: ref*, fresh, api_key |
channel_outliers | A channel's own outliers (scope own), or outliers for a channel like it from other
channels in the shared index (scope niche, 3x and over by default). Free. Same as
GET /v1/channels/{ref}/outliers. params: ref*, scope, min_multiple, limit, api_key |
similar_channels | Channels in the shared index closest to this one by the meaning of their titles, else
by shared words, with a similarity 0 to 1. Free. Same as GET /v1/channels/{ref}/similar. params: ref*, limit, api_key |
search_channels | Channels by name or handle: the shared index first, then YouTube's own channel search.
Free. Same as GET /v1/channels/search. params: q*, limit, api_key |
niche_report | A niche report counted from the shared index: videos, channels, median views, the share
at 10x and over, the 75th percentile multiple, top outliers and channels, by month. Free.
Same as GET /v1/niches/{slug}. params: slug*, api_key |
list_niches | The niche explorer: every niche reported, with its headline numbers. Free. Same as
GET /v1/niches. params: limit, api_key |
video_stats | A video's views per hour and its history from the shared index (new, rising and
tracked videos read hourly, the rest daily); a video the index lacks is read now. Free.
Same as GET /v1/videos/{video_id}/stats. params: video_id*, api_key |
list_winners | Real title and thumbnail changes on other channels: both versions (the pictures as
URLs), views per hour before and 24 to 72 hours after, the lift and when the spike came.
Free. Same as GET /v1/winners. params: type, min_lift, min_views, min_vph_before, sort, limit, cursor, api_key |
create_tracker | Make a tracker of up to 50 channels: hourly reads of their newest uploads, alerts when
one reaches the multiple (default 3x its channel) or views per hour, in the app and by
email. 1 credit a tracked channel a day. Same as POST /v1/trackers. params: name*, channels, visibility, multiple_threshold, vph_threshold, alert_email, team, api_key |
list_trackers | Your trackers, or every public one. Free. Same as GET /v1/trackers. params: scope, api_key |
get_tracker | One tracker and its channels. Same as GET /v1/trackers/{tracker_id}. params: tracker_id*, token, api_key |
update_tracker | Rename a tracker, share it, change its alert lines, or turn its daily ideas on. Same as
PATCH /v1/trackers/{tracker_id}. params: tracker_id*, name, visibility, multiple_threshold, vph_threshold, alert_email, daily_ideas, api_key |
delete_tracker | Delete one of your trackers. Same as DELETE /v1/trackers/{tracker_id}. params: tracker_id*, api_key |
add_to_tracker | Add channels to one of your trackers. Same as POST /v1/trackers/{tracker_id}/channels. params: tracker_id*, channels*, api_key |
remove_from_tracker | Take a channel off one of your trackers. Same as DELETE
/v1/trackers/{tracker_id}/channels/{ref}. params: tracker_id*, ref*, api_key |
tracker_feed | A tracker's channels' uploads, strongest first. Free. Same as GET
/v1/trackers/{tracker_id}/feed. params: tracker_id*, token, sort, days, limit, api_key |
clone_tracker | Copy a public or shared tracker into a private one of yours. Same as POST
/v1/trackers/{tracker_id}/clone. params: tracker_id*, token, api_key |
tracker_alerts | Your tracker alerts, newest first, with the unread count. Free. Same as GET
/v1/trackers/alerts. params: unread_only, mark_read, limit, api_key |
create_alert | Save a search checked daily or weekly; a new video at your line (default 3x its
channel) is a hit, emailed, with a Monday digest. 1 credit a check. Same as
POST /v1/alerts. params: query*, min_multiple, min_vph, frequency, email, api_key |
list_alerts | Your saved searches and their newest hits. Free. Same as GET /v1/alerts. params: api_key |
get_alert | One saved search and its hits. Same as GET /v1/alerts/{alert_id}. params: alert_id*, api_key |
update_alert | Change a saved search: its words, line, frequency or email. Same as PATCH
/v1/alerts/{alert_id}. params: alert_id*, query, min_multiple, min_vph, frequency, email, daily_ideas, api_key |
delete_alert | Delete a saved search. Same as DELETE /v1/alerts/{alert_id}. params: alert_id*, api_key |
run_alert | Check a saved search now, as a job (read it with get_job). 1 credit. Same as
POST /v1/alerts/{alert_id}/run. params: alert_id*, api_key |
create_webhook | Post every new tracker alert and saved-search hit to your https URL, signed with the
secret this returns once (X-HD-Signature). Same as POST /v1/webhooks. params: url*, events, api_key |
list_webhooks | Your webhooks with their events and state (never the secret). Same as GET /v1/webhooks. params: api_key |
delete_webhook | Delete one of your webhooks. Same as DELETE /v1/webhooks/{webhook_id}. params: webhook_id*, api_key |
test_webhook | Send one signed test delivery now and read what your URL answered. Same as
POST /v1/webhooks/{webhook_id}/test. params: webhook_id*, api_key |
webhook_deliveries | A webhook's deliveries, newest first, with status and your URL's answers. Same as
GET /v1/webhooks/{webhook_id}/deliveries. params: webhook_id*, limit, api_key |
video_scorecard | Everything the index knows about one video: the multiple, views per hour and its
history, real tags, title and thumbnail changes, our reads, similar videos. Free. Same as
GET /v1/videos/{video_id}/scorecard. params: video_id*, api_key |
list_trends | Rising words and phrases in the shared index's titles, this window against the one
before, with counts and growth. Free. Same as GET /v1/trends. params: window, api_key |
list_formats | Title formats of the last 90 days with their median multiple, share over 1.5x, adoption
and examples, ordered by the Wilson lower bound of that share (computed_from). Formats with at
least 8 measured videos from 3 channels (each shows measured beside videos); include_small lists
down to 3 from 2. Free. Same as GET /v1/formats. params: include_small, api_key |
format_videos | One title format's videos, strongest first. Free. Same as GET /v1/formats/{format_id}. params: format_id*, limit, api_key |
daily_ideas | Your daily idea sets (turn them on per saved search or tracker with daily_ideas), each
idea with the real finds behind it, none repeated within a week. Same as
GET /v1/ideas/daily. params: source_id, days, api_key |
create_agent | An agent that runs a Video Review on each new long upload of a tracker's channels,
inside a monthly credit budget. Same as POST /v1/agents. params: tracker_id*, name*, monthly_budget*, api_key |
list_agents | Your agents with their budgets and this month's spend. Free. Same as GET /v1/agents. params: api_key |
get_agent | One agent and its reviews (done, skipped or failed, and why). Same as
GET /v1/agents/{agent_id}. params: agent_id*, api_key |
update_agent | Change an agent's name or monthly budget, or pause it. Same as PATCH /v1/agents/{agent_id}. params: agent_id*, name, monthly_budget, active, api_key |
delete_agent | Delete one of your agents. Same as DELETE /v1/agents/{agent_id}. params: agent_id*, api_key |
get_skeleton | The skeleton of a long find's whole video, heard by Scribe v2: sections, re-hooks, open loops, payoffs, sponsor and call-to-action spans, the outro, the timed lines. Builds it once for 5 credits as a paid call (status pending; read it with get_call); after that answers the stored one free. Same as POST and GET /v1/finds/{find_id}/skeleton. params: find_id, idempotency_key, api_key |
review_video | Video Review of any public long video (15 credits): five ranked fixes with times and the counted fact behind each, six sub-scores each with what it is computed from, the hook scored and rewritten (labelled as written), the curve (YouTube's replay peaks, not retention; your Studio curve via graph_points; else predicted, not measured), the story with gap rules, pace and loudness per section, the nex params: url, graph_points, idempotency_key, api_key |
read_retention_graph | Read a YouTube Studio audience retention screenshot (base64 PNG or JPEG) into 100 points and the 21 marks it was read from (1 credit). Not the chart is 422 not_a_retention_chart, free. Same as POST /v1/review/graph. params: image, idempotency_key, api_key |
review_hook | Hook Review of your own opening (3 credits): a YouTube link (its first minute heard by Scribe v2) or a pasted script, scored out of 10 from named counted parts, a verdict per beat, and the promise check against your title and thumbnail words. Same as POST /v1/review/hook. params: url, script, title, thumbnail_words, idempotency_key, api_key |
write_hook | Hook Creator (1 credit): an opening for your subject as beats with seconds counted from their words and a shot plan per line (said, shown, on screen, sound, delivery), labelled as written. Same as POST /v1/openings. params: subject, hook_type, idempotency_key, api_key |
write_script | Script Writer (10 credits): hooks, the plan's sections with re-hooks and payoffs, the script, its runtime counted from its words, machine-sounding lines flagged, a fact-check list, Markdown. Runs as a job (get_call reads it). Same as POST /v1/scripts. params: subject, minutes, audience, idempotency_key, api_key |
review_script | Script Review (3 credits): your pasted script read like a Video Review on estimated times, plus machine-sounding lines and a fact-check list. Runs as a job. Same as POST /v1/scripts/review. params: script, title, idempotency_key, api_key |
review_edit | Edit Review of a cut before upload (25 credits; an unlisted or public YouTube link up to 60 minutes): cuts a minute, long shots, dead air, sound changes, on-screen text, and the notes as Premiere CSV, Resolve EDL and FCPXML markers. Runs as a job. Same as POST /v1/review/edit; to review the file itself (when YouTube refuses our servers the link is refused free with upload_instead), send it to POST params: url, idempotency_key, api_key |
write_upload_pack | The upload pack (1 credit) for a long find or your video: a description with chapters that pass YouTube's rules, tags and hashtags. Runs as a job. Same as POST /v1/seo. params: find_id, url, links, idempotency_key, api_key |
clean_recording | The talking-head cleaner (15 credits), like 1of10's AutoCut: silences tightened, retakes, false starts, stutters and fillers cut with a reason on every cut, other microphones or cameras synced to the first, as Premiere XML, FCPXML and a CMX 3600 EDL. Takes 1 to 4 file_id values staged with POST /v1/clean/files (a chat cannot send the file itself). Runs as a job; get_call reads it. Same as POST /v1 params: files, idempotency_key, api_key |
trending_shorts | Trending Shorts: the short videos (TikToks, Instagram Reels, YouTube Shorts) rising
now on a subject, fastest first. Each item has video_id, platform, url, cover_url,
creator, caption, plays, posted_at, age_hours, plays_per_hour (plays over the hours
since posting, at least one), multiple and multiple_basis (plays over the creator's
usual: the median of their latest videos, or TikT params: subject, platform, window, api_key |
review_short | Rate my Reel or Short: read one public short the way Hook Detector reads a clip (its
first frames, its words heard by ElevenLabs Scribe v2) and rate it against the real
finds on its subject (the Short form search over the last 30 days, ranked by their
multiple over the creator's usual). Returns review_id, url, platform, video_id, subject,
subject_from, clip (first_line, first_word_ params: url, subject, idempotency_key, api_key |
research_keywords | Keyword research for YouTube. volume: always estimated (YouTube publishes no search
counts): estimated_monthly_searches with a range, a 0 to 100 score and band, its source
(Google Trends with the YouTube filter against fixed anchors; or, when Trends is busy,
YouTube autocomplete and the top results' views) and basis. competition: 0 to 100 counted
from the top 10 long-form results ( params: keyword, country, language, idempotency_key, api_key |
comment_insights | What a subject's audience asks and struggles with: the top comments of its outliers
(videos that beat their own channel; or your video_ids, or a channel's best uploads),
grouped into questions, pain points and requests. clusters: label, kind (question,
pain_point, request, other), count (comments in the group, counted in code, never by the
model), likes, videos, and quotes: two rea params: subject, video_ids, channel, idempotency_key, api_key |
find_sponsors | Who sponsors the channels on a subject: in the descriptions of its outliers, sponsor
lines, promo codes and offer links found in code, plus Scrape Creators' sponsor read of
videos YouTube marks as paid promotion, each named by one model read and kept only when
the brand's name is in its own line. sponsors: brand, kind (sponsor, affiliate, other),
channel_count and video_count (coun params: subject, idempotency_key, api_key |
get_team | Your team, or team null: its name, pool (credits), seats, each member's name and role.
The owner also sees every member's email, monthly cap and spend, open invites (never
their links) and the newest 50 charges to the pool (who, what kind, credits, when; never
what it was about). your_credits is your own balance, untouched while you are a member.
Free. Same as GET /v1/team. params: api_key |
create_team | Create a team this account owns, funding its pool from your balance with credits
(402 when you hold less). Members' spending comes from the pool; you keep spending your
own balance. 409 already_in_team. Needs admin. Free. Same as POST /v1/team. params: name*, credits, api_key |
move_team_credits | Move credits between your balance and the team's pool; 402 when the side giving holds
less, and nothing moves. Owner only. Needs admin. Free. Same as POST /v1/team/credits. params: credits*, direction*, api_key |
invite_to_team | Invite someone: returns link (and its token), a single-use page valid 7 days, shown
here only, and emailed to that address (emailed true; when false, give the link to the
person yourself). Someone signed in with
Google must hold that email to accept. Owner only. Needs admin. Free. Same as POST
/v1/team/invites. params: email*, api_key |
revoke_team_invite | Revoke an open invite: its link stops working at once. Owner only. Needs admin. Free.
Same as DELETE /v1/team/invites/{invite_id}. params: invite_id*, api_key |
view_team_invite | What an invite joins, before accepting: the team's name, who invited you, its seats,
when the link expires, and whether you are signed in with the invited email (null for an
account with no email). Free. Same as GET /v1/team/invites/{token}. params: token*, api_key |
accept_team_invite | Join the team an invite names. From then on what you spend comes from the team's pool;
your own runs stay private and your own balance waits for you. Each link works once
(409 invite_used) for 7 days (410 invite_expired). Needs admin. Free. Same as POST
/v1/team/invites/{token}/accept. params: token*, api_key |
remove_team_member | The owner removes a member; anyone leaves with member_id "me". A removed member's next
spend comes from their own balance, never the pool. The owner leaving with members is 409
team_has_members; alone it ends the team and returns the pool. Needs admin. Free. Same as
DELETE /v1/team/members/{member_id}. params: member_id*, api_key |
set_team_member_cap | Set a member's monthly cap on the pool (null removes it). A run started near the cap
holds only what is left, so the cap is never passed mid-run (403 team_cap_reached below a
run's minimum or a tool's price). Owner only. Needs admin. Free. Same as PATCH
/v1/team/members/{member_id}. params: member_id*, monthly_cap*, api_key |
thumbnail_attention | Where the eye is predicted to land on a thumbnail: the picture with a heatmap over it (PNG,
base64), a 16 by 9 grid, the peak, the share in each third, the concentration and the share in
YouTube's length corner. UNISAL (AUC 0.895 on MIT1003): faces draw it strongly, printed words
less than people read them; a prediction, not a click-through rate. Free. Same as POST
/v1/thumbnails/a params: thumbnail, video_url, api_key |
create_poll | Put 2 to 4 packages to Hook Detector's users, who pick the one they would click, blind.
Closes at votes_wanted or after 7 days. 2 credits, given back when a picture cannot be
stored. Results with get_poll. Same as POST /v1/polls. params: options*, question, subject, votes_wanted, idempotency_key, api_key |
list_polls | Your package votes, newest first, with their results so far. Free. Same as GET /v1/polls. params: api_key |
get_poll | One poll: yours with votes, shares, 95% intervals, the leader once the votes separate, the
slots and the reasons; or one you voted on with its shares. Free. Same as GET
/v1/polls/{poll_id}. params: poll_id*, api_key |
delete_poll | Delete your poll, its votes and its pictures. Free. Same as DELETE /v1/polls/{poll_id}. params: poll_id*, api_key |
next_poll | A poll of another Hook Detector user waiting for your vote (not one you passed in skip): its
options in an order of your own, no counts; poll null when none is waiting. Free. Same as
GET /v1/polls/next. params: skip, api_key |
vote_poll | Vote on a poll with the slot you picked, and an optional reason. One vote an account, never
on your own or your team's poll. Answers the shares so far. Free. Same as POST
/v1/polls/{poll_id}/vote. params: poll_id*, slot*, reason, api_key |
close_poll | End your poll now: no more votes, the votes so far kept with its results. Free. Same as
POST /v1/polls/{poll_id}/close. params: poll_id*, api_key |
video_badges | Badges for up to 50 YouTube videos at once, as the Chrome extension shows them on every
card: views, the multiple over the channel's usual views (long against long uploads, Shorts
against Shorts) with its band, and views per hour with its basis. Ids with no badge are in
unread with why. Free. Same as GET /v1/videos/badges. params: ids*, api_key |
list_research | The research findings counted from Hook Detector's shared index of public YouTube data:
openings (which openings sit before a steeper or flatter first minute of YouTube's "most
replayed" heatmap, replay intensity, not retention), title-devices (which title devices go with
higher multiples, by niche) and title-thumbnail-overlap (title and thumbnail word overlap against
the multiple) params: none |
get_research | One research page: every claim with the first run's and the second run's numbers (each run a
sample of different channels), n per run and per cell, shown_a and shown_b (over the sample
bar), reproduced (true, false, or null for too few) and direction, plus measures naming what
each number is computed from. 404 page_not_found for an unknown slug, 422 for a malformed one.
No key need params: slug* |
Entries describe changes in tool definitions. They are not statements about a server, its quality or its author. The grade measures how the tool definitions fit model providers (token cost, schema compatibility, confusable names) as scored by the ToolFit engine at the time of the listing. JSON: append .json. Opt-out: how or hello@youraitools.co.