searchtok

docs

searchtok api

tiktok and instagram reels research for agents and scripts: the outliers, hooks and creators in any niche, every number from real posts.

searchtok finds the tiktoks and instagram reels worth copying. give it a niche, an app, a website or a handle and it finds the outliers (posts with far more views than the account usually gets), the hooks behind them and the creators making them.

every endpoint is a searchtok tool, the same ones our own agent uses. views, outlier scores and baselines are worked out in code from real posts, never guessed by a model, and every result links back to the searchtok dashboard.

ways in

  • rest api https://searchtok.app/api/v1

    live. for any agent or script that can send http: n8n, make, manus, your own code.

  • mcp server https://searchtok.app/mcp

    live. streamable http, for claude, chatgpt, claude code, cursor, codex, openclaw and any agent that takes a remote mcp server. add the url and sign in (oauth), or send your api key as Authorization: Bearer st_live_....

    in claude code:

    claude mcp add --transport http searchtok https://searchtok.app/mcp --header "Authorization: Bearer $SEARCHTOK_API_KEY"
  • cli npx searchtok
  • agent skill npx skills add Mitchell2398/searchtok-agent

quick start

  1. sign in and make an api key at searchtok.app/app/settings/keys
  2. keep it in an environment variable:
    export SEARCHTOK_API_KEY=st_live_...
  3. check it works. this one is free:
    curl https://searchtok.app/api/v1/usage \
      -H "Authorization: Bearer $SEARCHTOK_API_KEY"

keys

send your key on every request as Authorization: Bearer st_live_.... make and revoke keys at searchtok.app/app/settings/keys. every endpoint needs a searchtok plan, except usage and profile, which always work so an agent can tell you where you stand.

credits

each call costs credits from one pool, shared by every way in. every signed-in response says what it used and what's left in two headers:

  • credits-used: credits this request used
  • credits-left: credits left after it

a call that fails is refunded. send the same Idempotency-Key header to retry a call without paying twice. credit costs are provisional and may change before launch.

rate limit

up to 60 requests a minute per key. past that you get a 429 with a Retry-After header.

errors

every error has the same shape. hint says what to try next.

{
  "error": {
    "code": "no_credits",
    "message": "search_content costs 0 credits and 12 are left",
    "hint": "..."
  }
}
codestatuswhat it means
bad_input400the request doesn't match the input schema; message says what's wrong
unsupported400that platform or kind of link isn't supported by this endpoint
unauthorized401no key, or the key isn't valid or was revoked
no_plan402the account has no searchtok plan
no_credits402not enough credits left for this call
not_allowed403this key can't do that
not_found404the post, account, run or endpoint doesn't exist (or is private)
unknown_tool404no such endpoint
budget_exceeded422the call needed more data than one call may use; narrow it down
rate_limited429more than 60 requests in a minute with this key
internal500something broke on our side; credits are refunded
not_available503switched off for now (research has a kill switch and a daily cap)
unavailable503tiktok or instagram data couldn't be fetched right now; credits are refunded

endpoints

requests and responses are json. an endpoint's input is its tool's input, and its response is the tool's output. credit costs are provisional and may change before launch.

POST/api/v1/search

search tiktok and reels

credits: 20 per querysearch_content

Find the TikToks and Instagram Reels that did best for a topic or niche, ranked by outlier score (a post's views ÷ its account's usual views). searchtok's main tool.

Use it for: what's working in a niche, viral examples of a format, hooks and ideas to copy.

Don't use it for: a known account (get_account), a known post (analyze_post), posts like a given post (find_similar), finding creators (find_accounts).

Each query runs several searches plus searchtok's index, removes repeats and scores each post. Several angles or niches? Pass them together as queries (up to 5): they run at the same time, much faster than a call each.

Returns compact rows (id, url, handle, views, outlier_score with its explanation, caption, hook, format), what was searched and a dashboard link. Top rows carry their hook word for word, so analyze_post is rarely needed just to quote one. Paid posts are flagged paid.

input

query string
What to look for, in the words people would search on TikTok: a niche, topic or format ("habit tracker app", "smile transformation"). Short beats long.
queries string[]
Up to 5 searches in one call, run at the same time (several angles on a niche, or several niches). Faster than one call per query; each query costs what a single search costs. Rows say which queries found them.
platforms ("tiktok" | "instagram")[]
Default: both
timeframe "7d" | "30d" | "90d" | "1y"
Only posts from this long ago or newer. Default: any time
language string
Two-letter language, e.g. "en". Posts in other languages are dropped; posts whose language is unknown are kept
region string
Two-letter country that biases TikTok results (it doesn't filter them)
limit integer
Rows to return. Default 15 (more for several queries). Results are cut to about 2k tokens (plus about 1k per extra query); the rest are at link

returns

search_id string required
This search's id in searchtok
rows object[] required
Best first: id, platform, url, handle, posted_at, views, outlier_score, outlier_explained, caption, hook, format, why_matched
total_found number required
Distinct posts found before the limit
searched object[] required
Each search that ran, and how many posts it returned
missed string[]
Calls that failed or were too slow. Results may be thinner than usual
left_out number
Weaker rows (under 1x their account's usual views, or no score) left out. They're at link
truncated number
Rows left out to keep this result short. They're at link
note string
Said when there's nothing to show or no scores, with what to try
link string required
This search in the searchtok dashboard

example

curl -X POST https://searchtok.app/api/v1/search \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"habit tracker app"}'
example response (real output, lists cut short)
{
  "search_id": "00000000-0000-4000-8000-000000000001",
  "rows": [
    {
      "id": "tiktok:7377548155597950251",
      "platform": "tiktok",
      "url": "https://www.tiktok.com/@spaceyflower/video/7377548155597950251",
      "handle": "spaceyflower",
      "posted_at": "2024-06-07",
      "views": 565678,
      "outlier_score": 1457.9,
      "outlier_explained": "1457.9x this account's usual views (median 388 over its last 20 posts)",
      "caption": "#habittracker #habittracker2024 #BulletJournal #bulletjournaling #yearinpixels…",
      "hook": null,
      "format": "video",
      "cover_url": "https://searchtok.app/api/c/tiktok:7377548155597950251",
      "why_matched": [
        "#habittracker"
      ]
    },
    "... 14 more"
  ],
  "total_found": 111,
  "searched": [
    {
      "platform": "instagram",
      "search": "reels search \"habit tracker app\"",
      "found": 9
    },
    "... 5 more"
  ],
  "link": "https://searchtok.app/app/searches/00000000-0000-4000-8000-000000000001"
}
POST/api/v1/accounts/find

find creators and brands

15 creditsfind_accounts

Find TikTok or Instagram creators and brands in a niche, with how well their posts do: followers, usual (median) views and outlier rate (how often a post gets 3x+ their usual views).

Use it for: creators to learn from or partner with, competitors in a niche, accounts that reliably go viral.

Don't use it for: one account you already know (get_account), a brand's website or name (analyze_brand), posts (search_content).

Returns up to 8 accounts (6 on Instagram), most reliable outlier-makers first, each with id, handle, url, followers, median views, outlier rate and posts per week. Never returns or infers gender, ethnicity or age.

input

query string required
A niche or topic ("habit tracker app"), or a name to look up
platform "tiktok" | "instagram"
Default: tiktok

returns

rows object[] required
missed string[]
truncated number
note string

example

curl -X POST https://searchtok.app/api/v1/accounts/find \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"habit tracker app"}'
example response (real output, lists cut short)
{
  "rows": [
    {
      "id": "tiktok:7597922150545507350",
      "platform": "tiktok",
      "handle": "completerapp",
      "display_name": "Completer - Habit Tracker",
      "url": "https://www.tiktok.com/@completerapp",
      "followers": 667,
      "verified": null,
      "bio": null,
      "median_views": 674,
      "posts_sampled": 30,
      "baseline_explained": "median 674 views over its last 30 posts (2+ days old)",
      "outlier_rate": 0.17,
      "posts_per_week": 1.1
    },
    "... 7 more"
  ]
}
GET/api/v1/accounts/{platform}/{handle}

look up an account

3 creditsget_account

Look up one TikTok or Instagram account: profile, its usual (median) views, outlier rate, posting rate, format mix and its best recent posts by outlier score.

Use it for: checking a creator or competitor you already know by handle or url, and following up on an account from another searchtok result.

Don't use it for: finding accounts (find_accounts), a brand known only by website or name, or comparing brands (analyze_brand).

Returns the profile, numbers (all worked out from its latest 30 posts) and up to 5 top recent posts with outlier scores and ids for analyze_post.

input

platform "tiktok" | "instagram" required in the path
tiktok or instagram
handle string required in the path
The account's handle, with or without "@"

returns

account object required
numbers object required
top_outliers object[] required
Its best recent posts by outlier score
link string required

example

curl https://searchtok.app/api/v1/accounts/tiktok/completerapp \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY"
example response (real output, lists cut short)
{
  "account": {
    "id": "tiktok:7597922150545507350",
    "platform": "tiktok",
    "handle": "completerapp",
    "display_name": "Completer - Habit Tracker",
    "url": "https://www.tiktok.com/@completerapp",
    "followers": 667,
    "following": 493,
    "posts": 79,
    "likes_total": 13861,
    "verified": false,
    "bio": "Build better habits with a simple habit tracker. Download \"COMPLETER\" on the App Store. 📲 getcompleter.app"
  },
  "numbers": {
    "median_views": 674,
    "posts_sampled": 30,
    "baseline_explained": "median 674 views over its last 30 posts (2+ days old)",
    "outlier_rate": 0.17,
    "posts_per_week": 1.1,
    "format_mix": {
      "carousel": 0.87,
      "video": 0.13
    }
  },
  "top_outliers": [
    {
      "id": "tiktok:7616340301648563488",
      "platform": "tiktok",
      "url": "https://www.tiktok.com/@completerapp/photo/7616340301648563488",
      "handle": "completerapp",
      "posted_at": "2026-03-12",
      "views": 216733,
      "outlier_score": 344,
      "outlier_explained": "344x this account's usual views (median 630 over its last 29 posts)",
      "caption": "Discover my favorite iPhone apps for 2026 — handy tools to stay productive, org…",
      "hook": null,
      "format": "carousel",
      "cover_url": "https://searchtok.app/api/c/tiktok:7616340301648563488"
    },
    "... 4 more"
  ],
  "link": "https://searchtok.app/app/accounts/tiktok%3A7597922150545507350"
}
POST/api/v1/brands/analyze

analyse a brand

credits: 5 per brand (the brand plus each one compared)analyze_brand

Analyse a brand's or creator's organic TikTok and Instagram from its website, handle or name, optionally side by side with up to 3 others (compare).

Use it for: competitor research, 'how is X doing on TikTok', benchmarking your brand against others, a brand known only by its website.

Don't use it for: one handle when you only need its profile and top posts (get_account, cheaper), finding brands in a niche (find_accounts), ads (organic posts only).

A website is read for its TikTok and Instagram links; a name is looked up with TikTok account search (resolved_from says how, check it). Returns per account: followers, usual (median) views, outlier rate, posts per week, format mix, last-30-days vs previous-30-days posting and views, top outlier posts and quoted hooks of analysed posts. Every number is worked out in code; interpret them yourself.

input

website string
The brand's site, e.g. "acme.com". Its TikTok and Instagram links are read from the page
handle string
A TikTok or Instagram handle, e.g. "@acme"
platform "tiktok" | "instagram"
The handle's platform. Default: tiktok
name string
The brand's name, looked up with TikTok account search
compare object[]
Up to 3 other brands, same fields, analysed side by side

returns

brands object[] required
The brand first, then each one compared
missed string[]
link string required

example

curl -X POST https://searchtok.app/api/v1/brands/analyze \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"handle":"@completerapp","compare":[{"handle":"@thehabittracker"}]}'
example response (real output, lists cut short)
{
  "brands": [
    {
      "brand": "@completerapp",
      "resolved_from": "handle on tiktok",
      "accounts": [
        {
          "id": "tiktok:7597922150545507350",
          "platform": "tiktok",
          "handle": "completerapp",
          "url": "https://www.tiktok.com/@completerapp",
          "followers": 667,
          "median_views": 674,
          "posts_sampled": 30,
          "outlier_rate": 0.17,
          "posts_per_week": 1.1,
          "format_mix": {
            "carousel": 0.87,
            "video": 0.13
          },
          "change_30d": {
            "posts_last_30d": 2,
            "posts_prev_30d": 0,
            "median_views_last_30d": 1165,
            "median_views_prev_30d": null
          },
          "top_outliers": [
            {
              "id": "tiktok:7616340301648563488",
              "platform": "tiktok",
              "url": "https://www.tiktok.com/@completerapp/photo/7616340301648563488",
              "handle": "completerapp",
              "posted_at": "2026-03-12",
              "views": 216733,
              "outlier_score": 344,
              "outlier_explained": "344x this account's usual views (median 630 over its last 29 posts)",
              "caption": "Discover my favorite iPhone apps for 2026 — handy tools to stay productive, org…",
              "hook": null,
              "format": "carousel"
            },
            "... 2 more"
          ],
          "hooks": []
        }
      ]
    },
    "... 1 more"
  ],
  "link": "https://searchtok.app/app/brief?accounts=tiktok%3A7597922150545507350,tiktok%3A7285627514402653186"
}
POST/api/v1/posts/analyze

analyse a post

credits: 6 per postanalyze_post

Everything about a TikTok or Instagram post, by url or searchtok id. For several posts, pass them together as ids or urls (up to 8): they're analysed at the same time, much faster than one call each.

Use it for: breaking down why a post worked, quoting its hook or script, checking a post from another searchtok result or a link the user pasted.

Don't use it for: finding posts (search_content), posts like this one (find_similar), an account's overall numbers (get_account).

Returns fresh views, likes, comments, shares and saves, the account's usual views, the outlier score with its explanation, the transcript and, once analysed, on-screen text, spoken and on-screen hooks, format and structure (analysis_status says whether that has run). Hooks are quoted word for word from the post, never written by a model. With ids or urls, a list (posts), one per post, in order.

input

url string
The post's TikTok or Instagram url
id string
A searchtok post id from another result, e.g. "tiktok:7301234567890"
urls string[]
Several posts by url (up to 8 in all, with ids), analysed at the same time
ids string[]
Several posts by searchtok id (up to 8 in all, with urls), analysed at the same time

returns

no input.

example

curl -X POST https://searchtok.app/api/v1/posts/analyze \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://www.tiktok.com/@spaceyflower/video/7377548155597950251"}'
example response (real output, lists cut short)
{
  "post": {
    "id": "tiktok:7377548155597950251",
    "platform": "tiktok",
    "url": "https://www.tiktok.com/@spaceyflower/video/7377548155597950251",
    "handle": "spaceyflower",
    "posted_at": "2024-06-07",
    "caption": "#habittracker #habittracker2024 #BulletJournal #bulletjournaling #yearinpixels #ratemyday",
    "hashtags": [
      "habittracker",
      "... 5 more"
    ],
    "duration_s": 30.3,
    "format": "video",
    "sound": "original sound - neil.chapman1",
    "cover_url": "https://searchtok.app/api/c/tiktok:7377548155597950251"
  },
  "metrics": {
    "views": 565678,
    "likes": 8281,
    "comments": 66,
    "shares": 729,
    "saves": 2545,
    "views_per_day": 658,
    "engagement_rate": 0.016
  },
  "baseline": {
    "median_views": 388,
    "posts_sampled": 20,
    "confidence": "ok"
  },
  "outlier_score": 1457.9,
  "outlier_explained": "1457.9x this account's usual views (median 388 over its last 20 posts)",
  "transcript": {
    "status": "available",
    "text": "the reason why I wake up at 5:00am and I run every morning is it because I'm a Marathon runner or because I'm some kind of triathlete it's because I fucking hate running man I hate getting up early even more so I'm starting the day by building a non negotiable standard for myself which I've come to realize is the only way we can ever grow and improve when people say no one's coming to save you they're not talking about how no one's coming to help you reach your goals talking about how no one's coming to save you from yourself because without standards man we always lose direction and we always fall back to our lowest automatic systems binging procrastinating clinging to comfort",
    "cut": false
  },
  "on_screen_text": null,
  "spoken_hook": null,
  "on_screen_hook": null,
  "format_label": null,
  "second_format_label": null,
  "structure": null,
  "seen": null,
  "is_ad": null,
  "country": "US",
  "analysis_status": "not_available",
  "link": "https://searchtok.app/app/posts/tiktok%3A7377548155597950251"
}
POST/api/v1/similar

find similar posts

12 creditsfind_similar

Find posts like a given TikTok or Instagram post (same topic or format), ranked by outlier score.

Use it for: 'more like this', finding other creators doing the same format, checking whether a format works beyond one account.

Don't use it for: a topic in words (search_content), one post's details (analyze_post).

Searches the post's own hashtags and caption words on its platform, plus searchtok's index by meaning. Returns the same compact rows as search_content (the source post left out), with why_matched saying which seed found each. Paid posts are flagged paid.

input

url string
The post's TikTok or Instagram url
id string
A searchtok post id, e.g. "tiktok:7301234567890"
limit integer
Default 10

returns

source object required
rows object[] required
total_found number required
searched string[] required
missed string[]
truncated number
note string

example

curl -X POST https://searchtok.app/api/v1/similar \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"id":"tiktok:7377548155597950251","limit":10}'
example response (real output, lists cut short)
{
  "source": {
    "id": "tiktok:7377548155597950251",
    "url": "https://www.tiktok.com/@spaceyflower/video/7377548155597950251",
    "handle": "spaceyflower",
    "views": 565678
  },
  "rows": [
    {
      "id": "tiktok:7400516824174988590",
      "platform": "tiktok",
      "url": "https://www.tiktok.com/@spaceyflower/video/7400516824174988590",
      "handle": "spaceyflower",
      "posted_at": "2024-08-07",
      "views": 1360488,
      "outlier_score": 2846.2,
      "outlier_explained": "2846.2x this account's usual views (median 478 over its last 27 posts)",
      "caption": "#habittracker2024 #habittracker #BulletJournal #bulletjournaling #yearinpixels…",
      "hook": null,
      "format": "video",
      "cover_url": "https://searchtok.app/api/c/tiktok:7400516824174988590",
      "why_matched": [
        "#habittracker2024"
      ]
    },
    "... 9 more"
  ],
  "total_found": 37,
  "searched": [
    "tiktok #habittracker (20)",
    "... 1 more"
  ]
}
POST/api/v1/research

research a question

credits: 50 quick, 150 deepresearch

Hand a whole question to searchtok's own research agent, which runs many searches and writes a checked report, every claim citing real posts.

Use it when the user asks for a full research report, or wants a big question run in the background (depth deep, then get_research for the answer).

Don't use it for: most questions. Calling search_content, find_accounts and analyze_post yourself is faster, cheaper and shows each step. It costs the most credits.

Returns a summary, the posts it's based on (ids, outlier scores, quoted hooks) and a dashboard link. quick waits about 15s; deep returns at once with its search_id and link, and the answer is ready within about a minute (get_research).

input

question string required
The research question, in the user's words
depth "quick" | "deep"
quick: under 15s, only already-analysed posts. deep: up to a minute, analyses new posts. Default quick

returns

search_id string required
This run's id in searchtok
status "done" | "partial" | "running" required
partial: some data couldn't be fetched, see answer.gaps. running: a deep run, still working
answer any
The checked answer: summary, patterns (each with claims citing post ids, with their numbers and quoted hooks) and example posts, what was searched, gaps. Not set while running
posts any[]
More results, best first: id, url, handle, views, outlier_score, caption
events_url string
Live progress and the answer as server-sent events (deep runs)
link string required
This run in the searchtok dashboard
outage string
Set when the run has no answer because searchtok's side failed: its credits were given back
note string

example

curl -X POST https://searchtok.app/api/v1/research \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"question":"smile transformation"}'
example response (real output, lists cut short)
{
  "search_id": "00000000-0000-4000-8000-000000000001",
  "status": "done",
  "answer": {
    "summary": "Smile transformation videos work best as a clear before and after reveal, or as an emotional story about a person who hid their smile. Dentists also get reach from a rating question or a warning about bad veneers. No hooks were analysed, so none are quoted.",
    "groups": [
      {
        "pattern": "Rate-this-smile reveal",
        "why": "A direct question invites comments and replays, and a clinic can film it with any patient case.",
        "claims": [
          {
            "text": "A dentist's rate-this-smile veneers video reached 10.99M views, 226.7x the account's usual.",
            "post_ids": [
              "tiktok:7598707763442748703"
            ],
            "numbers": [
              {
                "post_id": "tiktok:7598707763442748703",
                "metric": "views",
                "value": 10989752
              },
              "... 1 more"
            ],
            "hooks": []
          },
          "... 1 more"
        ],
        "examples": [
          "tiktok:7598707763442748703",
          "... 1 more"
        ]
      },
      "... 3 more"
    ],
    "searched": [
      "smile transformation",
      "... 1 more"
    ],
    "gaps": [
      "TikTok only; Instagram not searched.",
      "... 3 more"
    ]
  },
  "posts": [
    {
      "id": "tiktok:7002262291064360197",
      "url": "https://www.tiktok.com/@austincosmeticdentistry/video/7002262291064360197",
      "handle": "austincosmeticdentistry",
      "views": 84080,
      "outlier_score": 81.8,
      "caption": "#beforeandafter #beforeafter #smile #smiledekedekho #makeover #transformation #…"
    },
    "... 18 more"
  ],
  "link": "https://searchtok.app/app/searches/00000000-0000-4000-8000-000000000001"
}
GET/api/v1/research/{search_id}

get a research answer

freeget_researchworks without a plan

Fetch a research run's answer by its search_id: a deep run that research started in the background, or any earlier run.

Use it when research returned status running, or the user asks about an earlier research run.

Don't use it for: search_content results (they come back in full straight away).

Returns the status and, once it's done, the same answer research returns, with a dashboard link. Free.

input

search_id string required in the path
The run's search_id, from POST /research

returns

search_id string required
question string required
depth "quick" | "deep" required
status "queued" | "running" | "done" | "partial" | "failed" | "cancelled" required
running: not finished yet, ask again in 20 to 30 seconds. partial: some data couldn't be fetched, see answer.gaps
answer any
The checked answer, the same shape research returns. Set once the run is done or partial
posts any[]
More results, best first
error string
link string required
This run in the searchtok dashboard
events_url string
Live progress as server-sent events, while it runs
created_at string required
finished_at string | null required
truncated number
note string

example

curl https://searchtok.app/api/v1/research/$SEARCH_ID \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY"
example response (real output, lists cut short)
{
  "search_id": "00000000-0000-4000-8000-000000000001",
  "question": "smile transformation",
  "depth": "deep",
  "status": "done",
  "answer": {
    "summary": "Smile transformation videos work best as a clear before and after reveal, or as an emotional story about a person who hid their smile. Dentists also get reach from a rating question or a warning about bad veneers. No hooks were analysed, so none are quoted.",
    "groups": [
      {
        "pattern": "Rate-this-smile reveal",
        "why": "A direct question invites comments and replays, and a clinic can film it with any patient case.",
        "claims": [
          {
            "text": "A dentist's rate-this-smile veneers video reached 10.99M views, 226.7x the account's usual.",
            "post_ids": [
              "tiktok:7598707763442748703"
            ],
            "numbers": [
              {
                "post_id": "tiktok:7598707763442748703",
                "metric": "views",
                "value": 10989752
              },
              "... 1 more"
            ],
            "hooks": []
          },
          "... 1 more"
        ],
        "examples": [
          "tiktok:7598707763442748703",
          "... 1 more"
        ]
      },
      "... 3 more"
    ],
    "searched": [
      "smile transformation",
      "... 1 more"
    ],
    "gaps": [
      "TikTok only; Instagram not searched.",
      "... 3 more"
    ]
  },
  "posts": [
    {
      "id": "tiktok:7002262291064360197",
      "url": "https://www.tiktok.com/@austincosmeticdentistry/video/7002262291064360197",
      "handle": "austincosmeticdentistry",
      "views": 84080,
      "outlier_score": 81.8,
      "caption": "#beforeandafter #beforeafter #smile #smiledekedekho #makeover #transformation #…"
    },
    "... 15 more"
  ],
  "link": "https://searchtok.app/app/searches/00000000-0000-4000-8000-000000000001",
  "created_at": "2026-10-16T16:11:50.841Z",
  "finished_at": "2026-10-16T16:11:50.844Z",
  "truncated": 3
}
POST/api/v1/ideas

content ideas

150 creditscontent_ideas

Content ideas for the user's profile, each built on one video in their niche that beat its account's usual views 2x+ and fits the user (plus up to 2 more posts in its format), with hooks quoted word for word and the beats to film.

Each call finds new videos: a video shown in an earlier set for the profile is never shown again.

Use it for: 'what should I post', a content plan, ideas in a given format ('talking head ideas') or from an account's posts.

Don't use it for: finding posts to study (search_content). Ideas never invent hooks or formats: fewer new videos means fewer ideas, said in note.

Takes about a minute. Returns the ideas with their post ids, outlier scores and quoted hooks, plus a dashboard link.

input

profile_id string
Which saved profile (get_profile). Default: the first
count integer
How many ideas, 1 to 8. Default 8
focus string
Narrow the ideas: a theme ("leg day"), a format ("talking head", "talking head fitness") or an account ("@acme": ideas from its posts)

returns

set_id string required
profile_id string | null required
status "running" | "done" | "thin" | "empty" required
thin: fewer new videos than ideas asked for; empty: none (the credits go back). running: started in the background (the dashboard)
focus string | null required
ideas object[] required
note string | null required
Said when there are fewer ideas than asked for, and why
formats number required
Formats among the fitting posts read
scanned number required
Posts checked
searched string[] required
dropped number required
Ideas the checks removed
link string required
These ideas in the searchtok dashboard

example

curl -X POST https://searchtok.app/api/v1/ideas \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
example response (real output, lists cut short)
{
  "set_id": "00000000-0000-4000-8000-000000000001",
  "profile_id": "00000000-0000-4000-8000-000000000001",
  "status": "thin",
  "focus": null,
  "ideas": [
    {
      "id": "idea-1",
      "title": "Home tour with a personal story",
      "format": "day in the life / vlog",
      "format_id": "day-in-the-life",
      "fits": {
        "text": "A house tour told with a real story gives home buyers and sellers in your area a reason to trust you, which suits a residential realtor.",
        "phrase": "a residential realtor",
        "brief_field": "what"
      },
      "why": [
        "It opens by saying plainly what it is: a house tour, and the same words appear on screen.",
        "... 3 more"
      ],
      "posts": [
        {
          "id": "tiktok:7649541016927735054",
          "platform": "tiktok",
          "url": "https://www.tiktok.com/@meredithboydd/video/7649541016927735054",
          "handle": "meredithboydd",
          "views": 3518505,
          "outlier_score": 2398.4,
          "outlier_explained": "2398.4x this account's usual views (median 1.5k over its last 20 posts)",
          "on_screen_hook": "let's do a house tour",
          "own": false
        },
        "... 2 more"
      ],
      "proof": 7,
      "beats": [
        {
          "text": "Open outside the home and say you are doing a house tour, with the same words on screen.",
          "post_id": "tiktok:7649541016927735054"
        },
        "... 4 more"
      ],
      "hooks": [
        {
          "text": "let's do a house tour",
          "post_id": "tiktok:7649541016927735054",
          "field": "on_screen"
        },
        "... 4 more"
      ]
    }
  ],
  "note": "only 1 proven format in your niche right now. more niche words in your brief find more.",
  "formats": 2,
  "scanned": 207,
  "searched": [
    "Instagram reels search \"realtor\" (10)",
    "... 13 more"
  ],
  "dropped": 1,
  "link": "https://searchtok.app/app/ideas?set=00000000-0000-4000-8000-000000000001"
}
POST/api/v1/profile/build

build a profile

10 creditsbuild_profile

Turn one link into the user's searchtok profile: an App Store or Play link, a website, a TikTok or Instagram handle, or a sentence about the business.

Use it when the user has no profile yet (get_profile is empty) or adds a new app, business or client. Agencies keep one profile per client.

Don't use it to research someone else's account (get_account, analyze_brand).

It reads the listing, site or account. Returns (and saves) the brief: type (app, service, creator, ecommerce or agency), what it is, who it's for, 5 to 10 niche phrases in the words people use on TikTok, content goal, language, region, its own accounts, and 3 to 5 lookalike TikTok accounts that account search returned (never made up). Building the same link again updates that profile.

input

input string required
What the profile is for: an App Store or Google Play link, a website ("acme.com"), a TikTok or Instagram handle or profile url ("@acme", "instagram @acme"), or a sentence ("i run a dog grooming van in leeds")
save boolean
Save it as one of the user's profiles. Default true. Building the same link again updates that profile

returns

profile_id string | null required
Pass it to content_ideas as profile_id. Null when save was false
saved "created" | "updated" | "not_saved" required
source object required
brief object required
missed string[]
Pages, accounts or searches that couldn't be read
link string required

example

curl -X POST https://searchtok.app/api/v1/profile/build \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"input":"opal.so"}'
example response (real output, lists cut short)
{
  "profile_id": "00000000-0000-4000-8000-000000000001",
  "saved": "created",
  "source": {
    "kind": "website",
    "url": "https://opal.so"
  },
  "brief": {
    "type": "app",
    "name": "Opal",
    "what": "Opal is a screen time and focus app for iPhone, iPad, Mac and Android. It blocks apps you choose, runs a focus timer and gives a daily score for how your tech use fits your wellbeing.",
    "who_for": "People who spend too much time on their phone and want to scroll less and focus more.",
    "niche": [
      "screen time app",
      "... 9 more"
    ],
    "content_goal": "downloads",
    "language": "en",
    "region": null,
    "own_accounts": [
      {
        "platform": "tiktok",
        "handle": "opal",
        "url": "https://www.tiktok.com/@opal",
        "followers": 10931,
        "median_views": 4433,
        "posts_per_week": 0.3,
        "found": "linked from opal.so"
      },
      "... 1 more"
    ],
    "lookalikes": [
      {
        "platform": "tiktok",
        "handle": "bepresent.app",
        "display_name": "BePresent | Screen Time App",
        "url": "https://www.tiktok.com/@bepresent.app",
        "followers": 10124,
        "verified": null,
        "bio": null,
        "why": "a screen time app, by its name",
        "found_with": "screen time app"
      },
      "... 4 more"
    ],
    "gaps": [
      "The material doesn't say which country they mainly serve. Posts mention the US, UK, Japan and Australia.",
      "... 2 more"
    ]
  },
  "link": "https://searchtok.app/app/profiles"
}
GET/api/v1/profile

get my profile

freeget_profileworks without a plan

The user's saved searchtok profile(s): what they make content for (an app, a business, a creator...), their niche, audience and language.

Use it first when a question depends on who the user is ('ideas for me', 'what should I post'), so searches match their niche and language.

Don't use it to look up other accounts (get_account). Free.

Returns each profile's id, type, name, link, language, region and brief.

input

no input.

returns

profiles object[] required
note string
link string required

example

curl https://searchtok.app/api/v1/profile \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY"
example response (real output, lists cut short)
{
  "profiles": [
    {
      "id": "00000000-0000-4000-8000-000000000001",
      "type": "app",
      "name": "example habit app (test data)",
      "source_url": "https://app.example",
      "language": "en",
      "region": null,
      "brief": {
        "note": "test data for this example",
        "niche": "habit tracker app"
      }
    }
  ],
  "link": "https://searchtok.app/app/profiles"
}
GET/api/v1/usage

check credits

freeget_usageworks without a plan

The user's searchtok plan, credits left, when they reset, and what each tool costs.

Use it before a long run of calls (or after a no_credits error) so you can warn the user before they run out. Free and always works, even without a plan.

Returns plan, plan_status, can_use_tools, credits_left, credits_used, resets_at, credit_costs and upgrade_url.

input

no input.

returns

plan string required
plan_status string required
can_use_tools boolean required
False without an active plan or with no credits left
credits_left number required
credits_used number required
Used this credit month; refunded calls don't count
monthly_allowance number required
The plan's monthly credits. 0 without a plan
period_start string | null required
When this credit month started (ISO date)
resets_at string | null required
When the plan renews and credits are topped up (ISO date). Null without a plan
by_surface object[] required
This month's credits per door: dashboard, mcp, cli, api
by_tool object[] required
This month's credits per tool, most first
credit_costs object required
What each tool costs
upgrade_url string required
Pick a plan or buy more credits
usage_url string required
The same numbers on the dashboard

example

curl https://searchtok.app/api/v1/usage \
  -H "Authorization: Bearer $SEARCHTOK_API_KEY"
example response (real output, lists cut short)
{
  "plan": "creator",
  "plan_status": "active",
  "can_use_tools": true,
  "credits_left": 1000,
  "credits_used": 0,
  "monthly_allowance": 1250,
  "period_start": "2026-10-16",
  "resets_at": "2026-11-03",
  "by_surface": [
    {
      "surface": "dashboard",
      "credits": 0,
      "calls": 0
    },
    "... 3 more"
  ],
  "by_tool": [],
  "credit_costs": {
    "search_content": 20,
    "find_accounts": 15,
    "get_account": 3,
    "analyze_brand": "5 per brand",
    "analyze_post": 6,
    "find_similar": 12,
    "research": "50 quick, 150 deep",
    "content_ideas": 150,
    "build_profile": 10,
    "get_profile": 0,
    "get_usage": 0
  },
  "upgrade_url": "https://searchtok.app/app/billing",
  "usage_url": "https://searchtok.app/app/usage"
}