Skip to content
For AI agents: a documentation index is available at /llms.txt. Every docs page is also available as markdown: add .md to its URL. To connect, read /agents.md.

API referenceResearch

Break down what works for a set of Creators

POST /v1/breakdowns

Research on Creators, not keywords: analyses each Creator's latest videos_per_creator Videos into one Digest of what works for them. A Video's outlier is its views over its Creator's median in the Run; lift tables use those ratios (lift_tables.basis: creator_median), so size does not skew them. Keyword fields are refused. Read the Run at /v1/research/{id}.

Open in Playground (no API Key needed)

Price

9 credits per Creator plus 20 credits per analysed Video, fresh or stored; at most 4,090 credits. Estimate and 402 check assume every Video is analysed; failed ones are free.

Supports "estimate": true in the body: the reply is the price in Credits and whether it would be cached, with no Run created and nothing charged.

A cached result costs the same as a fresh one; cached says which you got.

Parameters

NameInTypeRequiredDefaultDescription
Idempotency-Keyheaderstring Optional—1-255 printable ASCII characters. Replaying this key with the same payload returns the original Run (202 while it is still running); a different payload, or a different operation, is a 409 idempotency_conflict.

Request body

application/json

object

  • creators array of any of 2 shapes items 1 to 10 1 to 10 Creators of any Platforms, each named once. Or collection_id.
    • Option 1 object
      • platform string required one of tiktok, instagram, youtube, facebook The Creator's Platform.
      • handle string required length 1 to 200 The Creator's handle, with or without @.
    • Option 2 string A profile URL.
  • collection_id string Or a Creator Collection, frozen at Run start.
  • videos_per_creator integer value 1 to 50 Default 25 Recent Videos to read and analyse per Creator. Default 25, max 50; Creators × videos_per_creator at most 200.
  • intent string length 1 to 1000 Drops off-intent Videos read, unanalysed and free. None is read in their place. At most 1000 characters.
  • wait number value 0 to 120 Default 30 Seconds to hold the response open before returning a running Run to poll. Default 30, max 120.
  • max_credits integer value at least 0 As in the query.
  • estimate boolean If a source the call would read is unavailable and the cache cannot answer, the estimate adds unavailable (the { platform, capability } parts it cannot reach), or is a 503 source_unavailable when it can reach none.

Responses

200 OK

The Run finished: a research result with mode: creators.

any of 2 shapes

  • Option 1 object The envelope every charged operation answers with: { run } while the Run is running (plus poll_url on the 202), joined by result once it completes or error once it fails.
    • run object required Every charged operation creates a Run. The envelope is identical whether the result came back inline or was polled.
      • id string required
      • kind string required What was run, e.g. video_lookup.
      • status string required one of running, completed, partial, failed partial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
      • created_at string required RFC 3339.
      • completed_at string required nullable Null while the Run is still running.
      • charge_credits integer required What this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
      • list_price_credits integer required The full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
      • cached boolean required True when a stored result answered without a fresh fetch.
      • progress object What a running Research has done so far, refreshed as it works: its stage and the counts known by then, such as analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
        • stage string required one of keywords, searching, reading_creators, filtering, analysing, writing_digest
        • keywords integer value at least 0
        • creators integer value at least 0
        • creators_read integer value at least 0
        • searches integer value at least 0
        • found integer value at least 0
        • judged integer value at least 0
        • kept integer value at least 0
        • dropped_off_topic integer value at least 0
        • dropped_unsure integer value at least 0
        • shortlisted integer value at least 0
        • analysed integer value at least 0
        • updated_at string required
    • result object required
      • digest_version integer required
      • mode string one of keywords, creators What the research was seeded with: keywords (an intent) or creators (a breakdown). Absent means keywords.
      • intent string
      • keywords array of string
      • keyword_rationale string
      • coverage map of string required
      • digest object required
        • summary string required Two or three sentences answering the intent directly: what is working on this topic right now, across the videos analysed.
        • themes array of object required items 1 to 8
          • name string required Short label, three or four words.
          • share number required value 0 to 1 Fraction of the analysed videos that belong to this theme, 0-1.
          • description string required What the videos in this theme have in common.
          • video_ids array of string required video_id keys (platform:id) of the analysed videos that belong to this theme, exactly as given in the evidence.
        • hooks array of object required items at most 12
          • text string required The opening line, quoted VERBATIM from the evidence. Never paraphrase, never invent.
          • video_id string required video_id key (platform:id) of the video this hook is quoted from, exactly as given in the evidence.
          • hook_type string required The kind of hook, e.g. question, claim, negation, stat.
          • why_it_works string required One sentence.
          • template string length at least 1 The verbatim hook with its specifics (product, number, mistake, outcome, audience) replaced by short bracketed slots, every other word kept as spoken, e.g. "Stop [mistake] if you want [outcome]".
          • lift object nullable The lift_tables.hook_type row for the quoted video's analysed hook type, attached in code (never written by the model). Null when that video has no analysed hook type.
            • value string required The analysed hook type, or format + hook type, the row is keyed by.
            • video_count integer required
            • median_views number required nullable
            • median_engagement_rate number required nullable
            • views_lift number required nullable
            • engagement_lift number required nullable
            • low_confidence boolean required
        • sentiment object required
          • positive number required value 0 to 1
          • neutral number required value 0 to 1
          • negative number required value 0 to 1
          • note string required One sentence on what drives the distribution.
        • angles array of object required items 1 to 8
          • angle string required A content angle worth trying.
          • rationale string required Why the evidence supports it, referencing what was seen.
        • formulas array of object items at most 5
          • name string required Short label, three to five words.
          • recipe string required One line saying how to make it: the format, how it opens, and the order of its beats.
          • visual_format string required The visual format, copied exactly as it appears in lift_tables.visual_format.
          • hook_type string required The hook type, copied exactly as it appears in lift_tables.hook_type.
          • structure string required The beat structure the example videos share, as short beats joined by arrows, e.g. "problem → demo → result → CTA".
          • video_ids array of string required Up to 3 video_id keys (platform:id) of analysed videos that follow this formula, best performing first, exactly as given in the evidence.
          • lift object required nullable The lift_tables.format_hook row for this formula's visual format and hook type, attached in code (never written by the model): its video_count and lifts. The lift is for the format + hook type pair only; the structure is not bucketed. Null when no analysed video has that pair.
            • value string required The analysed hook type, or format + hook type, the row is keyed by.
            • video_count integer required
            • median_views number required nullable
            • median_engagement_rate number required nullable
            • views_lift number required nullable
            • engagement_lift number required nullable
            • low_confidence boolean required
        • gaps array of object items at most 5 Up to 5 things the audience asks for in the top 10 videos' comments that no analysed video addresses, each with verbatim quoted comments (and the video they came from) and a suggested angle. Empty when no comments were available. Absent on research recorded before gaps existed.
          • ask string required What the audience asks for or complains about, in one sentence, in your own words.
          • comments array of object required items 1 to 3
            • text string required A comment quoted VERBATIM from <comments>, character for character. Never paraphrase, never invent.
            • video_id string required video_id key (platform:id) of the video this comment was left under, exactly as given in <comments>.
          • angle string required A video someone could make that answers this ask, in one sentence.
      • lift_tables object Lift tables computed in code over the analysed videos: per visual format, hook type and length bucket, the video count, median views and engagement rate, and lift versus the whole set's median. The Digest quotes lifts only from these. Absent on research recorded before they existed.
        • basis string one of set_median, creator_median
        • set object required
          • video_count integer required
          • median_views number required nullable
          • median_engagement_rate number required nullable
        • visual_format array of object required
          • value string required The visual format, hook type, length bucket, or <format> + <hook type>.
          • video_count integer required
          • median_views number required nullable
          • median_engagement_rate number required nullable (likes + comments + shares + saves) / views.
          • views_lift number required nullable Median views of this row over the whole set's median views. Null when the set median is 0 or unknown.
          • engagement_lift number required nullable
          • low_confidence boolean required True when the row rests on fewer than 3 videos.
        • hook_type array of object required
          • value string required The visual format, hook type, length bucket, or <format> + <hook type>.
          • video_count integer required
          • median_views number required nullable
          • median_engagement_rate number required nullable (likes + comments + shares + saves) / views.
          • views_lift number required nullable Median views of this row over the whole set's median views. Null when the set median is 0 or unknown.
          • engagement_lift number required nullable
          • low_confidence boolean required True when the row rests on fewer than 3 videos.
        • length array of object required
          • value string required The visual format, hook type, length bucket, or <format> + <hook type>.
          • video_count integer required
          • median_views number required nullable
          • median_engagement_rate number required nullable (likes + comments + shares + saves) / views.
          • views_lift number required nullable Median views of this row over the whole set's median views. Null when the set median is 0 or unknown.
          • engagement_lift number required nullable
          • low_confidence boolean required True when the row rests on fewer than 3 videos.
        • format_hook array of object Visual format and hook type together, value as <format> + <hook type>: the rows the Digest's formulas take their lift from. Absent on research recorded before it existed.
          • value string required The visual format, hook type, length bucket, or <format> + <hook type>.
          • video_count integer required
          • median_views number required nullable
          • median_engagement_rate number required nullable (likes + comments + shares + saves) / views.
          • views_lift number required nullable Median views of this row over the whole set's median views. Null when the set median is 0 or unknown.
          • engagement_lift number required nullable
          • low_confidence boolean required True when the row rests on fewer than 3 videos.
      • breakdown object Breakdown only: the Creators read and how many Videos each returned, and those that could not be read.
        • videos_per_creator integer required Recent Videos asked for per Creator.
        • creators array of object required Every Creator read, in request order, each charged its fee.
          • platform string required
          • handle string required
          • id string required
          • videos_read integer required Videos read; fewer than videos_per_creator when ended.
          • ended boolean required True when the Creator's feed ran out before videos_per_creator.
        • failed array of object Creators that could not be read, charged 0, each with its problem code and detail. The Run is then partial.
          • platform string required
          • handle string required
          • code string required
          • detail string required
        • lift_videos integer Analysed Videos with a view count, of analysed_videos: the ranking and lift basis. The rest are unscored.
        • analysed_videos integer Videos analysed, of all the Creators read.
      • videos array of object required The top 25 videos of the ranked shortlist, in rank order. Every video the research delivered pages, with filters and sorting, at GET /v1/research/{id}/videos.
        • platform string required
        • id string required
        • url string required nullable
        • description string required
        • posted_at string required nullable
        • duration_seconds number required nullable
        • thumbnail_url string required nullable
        • hashtags array of string required
        • sound object required nullable
          • id string required
          • title string required nullable
          • author string required nullable Who made the sound, as the platform names them. Null when the platform did not say (Facebook never does).
          • is_original boolean required nullable True for the creator's own audio (a voiceover or original sound), false for a catalogue or library track. Null when the platform did not say, never false for unknown.
        • creator object required nullable
          • id string required
          • handle string required nullable
          • name string required
          • follower_count number required nullable
          • avatar_url string required nullable Our archived copy when there is one, else the platform's URL, which may be signed and expire. Download it rather than storing the link.
          • verified boolean required nullable The creator's verified badge, from their latest profile read, else from this video's read. Null when neither reported it.
        • region string required nullable Where the video was posted, as the platform reports it (a country code on TikTok). Null when not reported.
        • language string required nullable Platform-declared caption language, e.g. en (TikTok). Null when not reported.
        • title string required nullable The video's own title (YouTube, Facebook). description still starts with it on YouTube, as before. Null when the platform shows none or did not report it.
        • commerce object required nullable Platform-declared commerce: what the Platform itself says, never inferred from the content. Each flag is null when not reported, never false. The object is null when nothing in it was reported.
          • is_ad boolean required nullable The Platform marks the video as an ad (TikTok, Instagram).
          • paid_partnership boolean required nullable The Platform marks a paid partnership (TikTok, Instagram; on YouTube, its "Includes paid promotion" label).
          • affiliate boolean required nullable The Platform marks affiliate content (Instagram).
          • shop_url string required nullable The product link the video carries (TikTok Shop).
          • anchors array of object required The links the video carries under its caption (an editing template, a product, a place). Empty when none were reported.
            • kind string required The Platform's own anchor type id, e.g. 54.
            • label string required What the anchor shows, e.g. CapCut · Editing made easy.
        • people object required nullable Platform-declared people: accounts the Video itself mentions or names. On TikTok mentions are the caption's mentions; on Instagram they are the users the Video tags, then the accounts its caption names. Null when it named none.
          • mentions array of string required Handles the caption mentions (lowercased).
          • collaborators array of object required Co-authors the Platform names on the Video (an Instagram collab, a Facebook collaborator).
            • handle string required nullable
            • name string required nullable
        • location object required nullable The place the Video names (Instagram). Null when it named none or the read did not say.
          • id string required nullable The Platform's own place id. Null when not sent.
          • name string required The place, e.g. Central Park, New York.
        • topics object required nullable Platform-declared topics. Null when the Platform reported none.
          • keywords array of string required The creator's own tags (YouTube).
          • genre string required nullable The Platform's category, e.g. Education (YouTube).
          • labels array of string required The Platform's own category labels (TikTok).
        • chapters array of object required nullable The description's chapters, in order (YouTube). Null when the video has none or they were not reported.
          • title string required
          • start_seconds number required Where the chapter starts, in seconds from the start.
        • ai_generated boolean required nullable The Platform labels the video AI-generated (TikTok). Null when not reported.
        • snapshot object required nullable
          • at string required
          • views number required
          • likes number required
          • comments number required
          • shares number required
          • saves number required
        • scores object required nullable Null when the creator has no baseline yet.
          • outlier number required nullable Views over the creator's median views.
          • outlier_p90 number required nullable
          • percentile number required nullable Where this video sits in the creator's own sample, 0-100.
          • velocity object required nullable
            • views_per_hour number required
            • window string required
          • reason string required nullable always aged_out aged_out when the video is over 30 days old and Scores are null.
          • baseline object required The yardstick every Score on this creator is measured against.
            • median_views number required
            • p90_views number required
            • engagement_rate number required nullable
            • posts_per_week number required nullable
            • sample integer required
            • confidence string required one of high, low
            • source string required one of videos, follower_tier
            • computed_at string required nullable
            • stale boolean required True past 7 days; the next lookup refreshes it.
        • coverage string always partial Present only where the platform's index is best-effort.
      • creators array of object required The top 25 creators, by best outlier multiple, then views. Every creator the research recorded pages, with filters and sorting, at GET /v1/research/{id}/creators.
        • platform string required
        • id string required
        • handle string required nullable
        • name string required
        • follower_count number required nullable
        • avatar_url string required nullable The creator's avatar as their video carried it at collection time; may be a signed URL that expires. Null when not recorded.
        • video_count integer required
        • best_outlier number required nullable
        • median_views number required nullable The Creator baseline median views best_outlier was measured against, frozen at collection time. Null, never zero, when no video of theirs carried Scores.
        • total_views number required
        • video_ids array of string required
        • top_video_id string nullable Breakdown only: this Creator's top Video against their own median (platform:id). Null when none was analysed.
        • posts_per_week number nullable Breakdown only: posts per week over the Videos read. Null when their dates are unknown.
        • videos_read integer Breakdown only: Videos read for this Creator.
        • videos_analysed integer Breakdown only: Videos analysed of those read; 0 when the intent dropped all of them or every analysis failed.
      • hashtags array of object required The top 25 hashtags, by video count, then views. Every hashtag the research recorded pages, with filters and sorting, at GET /v1/research/{id}/hashtags.
        • value string required
        • title string nullable
        • platforms array of string required Every platform this tag was observed on in the shortlist. One rollup spans platforms; video_ids are platform:id if you want the split.
        • video_count integer required
        • total_views number required
        • video_ids array of string required
      • sounds array of object required The top 25 sounds, by video count, then views. Every sound the research recorded pages, with filters and sorting, at GET /v1/research/{id}/sounds.
        • value string required
        • title string nullable
        • platforms array of string required Every platform this tag was observed on in the shortlist. One rollup spans platforms; video_ids are platform:id if you want the split.
        • video_count integer required
        • total_views number required
        • video_ids array of string required
        • author string nullable Who made the sound, from the first video that named them. Null when none did; absent on research recorded before it existed.
        • is_original boolean nullable True for original audio, false for a catalogue track, so a trend sound can be told from a voiceover. Null when no video said; absent on research recorded before it existed.
      • research object required
        • requested integer required
        • completed integer required
        • failed integer required
        • cached integer required
        • fresh integer required
        • max_videos integer required
        • included_videos integer required
        • shortlisted map of integer Shortlist places per requested platform: a guaranteed part each, then the rest by how many on-topic candidates each had.
        • dropped_off_topic integer Candidates judged off-topic and dropped before the shortlist; never charged.
        • dropped_unsure integer Candidates whose relevance was unsure and that ranked too low to keep; never charged.
        • dropped_sample array of object Up to 10 dropped candidates, best-ranked first, with why each was dropped. Absent on research recorded before it existed.
          • video_id string required platform:id of the dropped video.
          • verdict string required one of off_topic, unsure
          • reason string required The relevance check's reason, short.
  • Option 2 object Returned instead of a Run when estimate=true. Nothing is charged. Operations with more to say about a quote add members; the two above are always present.
    • estimate_credits integer required What the call would be charged, in Credits.
    • cached boolean required Whether a stored result can already answer. It does not change the price.

200 · The Run finished: a research result with `mode: creators`.

{
  "run": {
    "id": "run_8f2c1ad04b",
    "kind": "research",
    "status": "completed",
    "created_at": "2026-09-08T09:14:02.418Z",
    "completed_at": "2026-09-08T09:14:04.930Z",
    "charge_credits": 1018,
    "list_price_credits": 1018,
    "cached": false
  },
  "result": {
    "digest_version": 5,
    "mode": "creators",
    "coverage": {
      "tiktok": "complete"
    },
    "digest": {
      "summary": "Cold plunge videos are travelling on measured personal diaries rather than on science explainers. The videos that break out open on an unimpressive first number and pay it off with a later one, and keep the discomfort on camera instead of cutting around it. Sentiment is broadly positive, with the negative share concentrated on the cost of equipment.",
      "themes": [
        {
          "name": "30-day diaries",
          "share": 0.45,
          "description": "One creator, one tub, a counter on screen, and the change stated as a number rather than a feeling.",
          "video_ids": [
            "tiktok:7300000000000000000"
          ]
        },
        {
          "name": "Before-workout plunging",
          "share": 0.2,
          "description": "Shorter clips arguing about timing relative to training, usually with a gym setting.",
          "video_ids": [
            "tiktok:7300000000000000042"
          ]
        }
      ],
      "hooks": [
        {
          "text": "Day one I lasted eleven seconds.",
          "video_id": "tiktok:7300000000000000000",
          "hook_type": "stat",
          "why_it_works": "An unimpressive concrete number sets up a payoff the viewer stays for.",
          "template": "Day one I lasted [small number] [unit].",
          "lift": {
            "value": "STORY",
            "video_count": 9,
            "median_views": 1840000,
            "median_engagement_rate": 0.0912,
            "views_lift": 1.6,
            "engagement_lift": 1.21,
            "low_confidence": false
          }
        }
      ],
      "sentiment": {
        "positive": 0.62,
        "neutral": 0.23,
        "negative": 0.15,
        "note": "Enthusiasm for the routine itself; the negative share is almost entirely the price of a tub."
      },
      "angles": [
        {
          "angle": "Open on the day-30 number and work backwards to day one.",
          "rationale": "Every diary in the shortlist that led with the outcome outperformed the ones that led with the method."
        }
      ],
      "gaps": [
        {
          "ask": "Viewers want a cold plunge setup that does not cost hundreds.",
          "comments": [
            {
              "text": "ok but what do I do if I can't afford a 600 dollar tub",
              "video_id": "tiktok:7300000000000000000"
            }
          ],
          "angle": "A 30-day diary on a chest freezer or bathtub build, with the receipt on screen."
        }
      ]
    },
    "videos": [
      {
        "platform": "tiktok",
        "id": "7300000000000000000",
        "url": "https://www.tiktok.com/@someone/video/7300000000000000000",
        "description": "3 minutes at 4°C every morning for 30 days. Here is what actually changed. #coldplunge #recovery",
        "posted_at": "2026-09-05T06:32:11.000Z",
        "duration_seconds": 41,
        "thumbnail_url": "https://p16-sign.tiktokcdn.com/obj/tos-cover-7300000000000000000.jpeg",
        "hashtags": [
          "coldplunge",
          "recovery",
          "morningroutine"
        ],
        "sound": {
          "id": "7180000000000000000",
          "title": "original sound - someone",
          "author": "someone",
          "is_original": true
        },
        "creator": {
          "id": "cre_9d4b2a7f1c",
          "handle": "someone",
          "name": "Someone",
          "follower_count": 184300,
          "avatar_url": "https://p16-sign.tiktokcdn.com/obj/tos-avatar-someone.jpeg",
          "verified": false
        },
        "region": "US",
        "language": "en",
        "title": null,
        "commerce": {
          "is_ad": false,
          "paid_partnership": null,
          "affiliate": null,
          "shop_url": null,
          "anchors": [
            {
              "kind": "54",
              "label": "CapCut · Editing made easy"
            }
          ]
        },
        "people": {
          "mentions": [
            "coldplungeco"
          ],
          "collaborators": []
        },
        "location": null,
        "topics": {
          "keywords": [],
          "genre": null,
          "labels": [
            "Fitness",
            "Health"
          ]
        },
        "chapters": null,
        "ai_generated": false,
        "snapshot": {
          "at": "2026-09-08T09:14:04.219Z",
          "views": 1284000,
          "likes": 143200,
          "comments": 2810,
          "shares": 9040,
          "saves": 21600
        },
        "scores": {
          "outlier": 4.21,
          "outlier_p90": 1.6,
          "percentile": 95,
          "velocity": {
            "views_per_hour": 6698.6,
            "window": "snapshot"
          },
          "reason": null,
          "baseline": {
            "median_views": 305000,
            "p90_views": 802000,
            "engagement_rate": 0.1342,
            "posts_per_week": 4.1,
            "sample": 20,
            "confidence": "high",
            "source": "videos",
            "computed_at": "2026-09-08T09:14:03.902Z",
            "stale": false
          }
        }
      },
      {
        "platform": "tiktok",
        "id": "7300000000000000042",
        "url": "https://www.tiktok.com/@anotherone/video/7300000000000000042",
        "description": "I tried cold plunging before every workout for a week. #coldplunge",
        "posted_at": "2026-09-06T13:04:52.000Z",
        "duration_seconds": 28,
        "thumbnail_url": "https://p16-sign.tiktokcdn.com/obj/tos-cover-7300000000000000042.jpeg",
        "hashtags": [
          "coldplunge",
          "gym"
        ],
        "sound": {
          "id": "7180000000000000099",
          "title": "Winter Air",
          "author": "Northbound",
          "is_original": false
        },
        "creator": {
          "id": "cre_1a77c0b3de",
          "handle": "anotherone",
          "name": "Another One",
          "follower_count": 21400,
          "avatar_url": null,
          "verified": null
        },
        "region": "GB",
        "language": "en",
        "title": null,
        "commerce": {
          "is_ad": false,
          "paid_partnership": null,
          "affiliate": null,
          "shop_url": null,
          "anchors": []
        },
        "people": null,
        "location": null,
        "topics": null,
        "chapters": null,
        "ai_generated": null,
        "snapshot": {
          "at": "2026-09-08T09:14:04.219Z",
          "views": 96200,
          "likes": 8140,
          "comments": 212,
          "shares": 401,
          "saves": 1180
        },
        "scores": null
      }
    ],
    "creators": [
      {
        "platform": "tiktok",
        "id": "cre_9d4b2a7f1c",
        "handle": "someone",
        "name": "Someone",
        "follower_count": 184300,
        "avatar_url": "https://p16-sign.tiktokcdn.com/obj/tos-avatar-someone.jpeg",
        "video_count": 3,
        "best_outlier": 4.21,
        "median_views": 305000,
        "total_views": 1611400,
        "video_ids": [
          "tiktok:7300000000000000000"
        ]
      }
    ],
    "hashtags": [
      {
        "value": "coldplunge",
        "platforms": [
          "instagram",
          "tiktok"
        ],
        "video_count": 34,
        "total_views": 18402000,
        "video_ids": [
          "tiktok:7300000000000000000",
          "instagram:C9xExampleShortcode"
        ]
      }
    ],
    "sounds": [
      {
        "value": "7180000000000000000",
        "title": "original sound - someone",
        "author": "someone",
        "is_original": true,
        "platforms": [
          "tiktok"
        ],
        "video_count": 4,
        "total_views": 2140000,
        "video_ids": [
          "tiktok:7300000000000000000"
        ]
      }
    ],
    "breakdown": {
      "videos_per_creator": 25,
      "creators": [
        {
          "platform": "tiktok",
          "handle": "glowwithmaya",
          "id": "6800000000000000101",
          "videos_read": 25,
          "ended": false
        },
        {
          "platform": "tiktok",
          "handle": "skinbyjo",
          "id": "6800000000000000102",
          "videos_read": 25,
          "ended": false
        }
      ]
    },
    "research": {
      "requested": 50,
      "completed": 50,
      "failed": 0,
      "cached": 6,
      "fresh": 44,
      "max_videos": 50,
      "included_videos": 0
    }
  }
}

200 · With `estimate=true`: the price, no Run, no charge.

{
  "estimate_credits": 1018,
  "cached": false
}

202 Accepted

Still running: { run }. Poll GET /v1/runs/{id}.

object

Still running. Poll poll_url (GET /v1/runs/{id}), waiting the 202's Retry-After seconds between polls.

  • run object required Every charged operation creates a Run. The envelope is identical whether the result came back inline or was polled. Its fields are on Poll or re-read a run.
  • poll_url string required format uri Absolute URL of GET /v1/runs/{id} for this Run, the body's copy of the 202's Location header for callers that never see headers (MCP). Present only while the Run is running.

202 · Example

{
  "run": {
    "id": "run_8f2c1ad04b",
    "kind": "research",
    "status": "running",
    "created_at": "2026-09-08T09:14:02.418Z",
    "completed_at": null,
    "charge_credits": 0,
    "list_price_credits": 0,
    "cached": false
  },
  "poll_url": "https://www.shortsintel.com/v1/runs/run_8f2c1ad04b"
}

400 Bad Request

invalid_request (a malformed id, wait, estimate or Idempotency-Key) or unsupported_platform, refused before any Run opens. Nothing is charged.

Codes: invalid_request, unsupported_platform. The problem body and every code are on Errors.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose. retryable and action say whether to retry and what to do next.

  • type string required
  • title string required
  • status integer required
  • code string required one of missing_authorization, invalid_key, key_revoked, key_expired, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, key_scope_insufficient, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, focus_unsupported_kind, not_found, comment_not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, max_credits_exceeded, key_spend_cap_exceeded, rate_limit_exceeded, concurrency_limit_exceeded, tracker_limit_exceeded, webhook_limit_exceeded, webhook_rotation_in_progress, collection_limit_exceeded, collection_name_taken, collection_kind_mismatch, media_unavailable, vendor_error, source_unavailable, service_unavailable, internal_error Stable machine-readable code.
  • detail string
  • errors array of object On invalid_request from a field that failed validation: one entry per problem, so you can find the field without parsing detail. Absent when no single field is at fault, e.g. a body that is not JSON.
    • path string required Dotted path of the field to fix, e.g. collection_ids.1 or cursor. Empty for an issue with the request body as a whole.
    • message string required What is wrong with that field.
  • request_id string The request this problem answers, the same as its X-Request-Id header. Quote it to support.
  • retryable boolean required Whether sending the same request again, after any wait named here, can succeed: true for a rate or concurrency limit, an upstream outage, an internal error or a Run not yet settled; false when the request must change or a person must act. Fixed per code.
  • action string required The next step, in one sentence.
  • remedy string What to do next, as the code's error reference page says it; fuller than action. On every problem a request answers with; a per-item error inside a result may omit it.
  • retry_after_seconds integer value at least 0 Seconds to wait before retrying; the same as the Retry-After header. On rate_limit_exceeded, concurrency_limit_exceeded, source_unavailable and service_unavailable.
  • expired_at string When the key expired. On key_expired.
  • resets_at string When the request window (rate_limit_exceeded) or the key's month (key_spend_cap_exceeded) resets.
  • limit integer The limit that was hit, on the *_limit_exceeded codes.
  • running integer Runs in flight. On concurrency_limit_exceeded.
  • active integer Active Trackers or webhook endpoints. On tracker_limit_exceeded and webhook_limit_exceeded.
  • requested integer Trackers the request would resume. On tracker_limit_exceeded from a Collection action.
  • count integer Collections held. On collection_limit_exceeded.
  • balance_credits integer The Balance, in Credits. On insufficient_balance.
  • required_credits integer What the call needs, in Credits (the worst case where quoted). On insufficient_balance.
  • max_credits integer The cap the call sent. On max_credits_exceeded.
  • estimate_credits integer The call's worst-case quote, in Credits. On max_credits_exceeded and key_spend_cap_exceeded.
  • cap_credits integer The key's monthly cap. On key_spend_cap_exceeded.
  • spent_credits integer The key's Charges this UTC month. On key_spend_cap_exceeded.
  • reserved_credits integer What the key's Runs in flight hold. On key_spend_cap_exceeded.
  • endpoints array of string The sources that could not answer. On source_unavailable.
  • endpoint string The source that could not answer. On source_unavailable.
  • candidates array of object The advertisers that carry the name, to ask again with. On advertiser_ambiguous.
  • supported_kinds array of string The kinds that are accepted. On kind_deprecated and focus_unsupported_kind.
  • duration_seconds number The video's length. On video_too_long.
  • max_duration_seconds number The longest video accepted. On video_too_long.
  • overlap_expires_at string When the previous secret stops working. On webhook_rotation_in_progress.
  • scope string always read_only The key's scope. On key_scope_insufficient.
  • required string always full The scope the call needs. On key_scope_insufficient.
  • collection_id string The Collection that already has the name. On collection_name_taken.
  • collection_kind string The Collection's kind. On collection_kind_mismatch.
  • kind string The kind that was offered. On collection_kind_mismatch.
  • run_id string The Run the Idempotency-Key already belongs to. On idempotency_conflict.
  • reason string A short machine-readable reason, where a code has several.
  • reference_id string Our reference for an unexpected failure, the same as request_id; quote it when reporting it.
  • run object The Run, on a failed Run's body, so its id is kept.
    • id string required
    • kind string required What was run, e.g. video_lookup.
    • status string required one of running, completed, partial, failed partial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
    • created_at string required RFC 3339.
    • completed_at string required nullable Null while the Run is still running.
    • charge_credits integer required What this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
    • list_price_credits integer required The full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
    • cached boolean required True when a stored result answered without a fresh fetch.
    • progress object What a running Research has done so far, refreshed as it works: its stage and the counts known by then, such as analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
      • stage string required one of keywords, searching, reading_creators, filtering, analysing, writing_digest
      • keywords integer value at least 0
      • creators integer value at least 0
      • creators_read integer value at least 0
      • searches integer value at least 0
      • found integer value at least 0
      • judged integer value at least 0
      • kept integer value at least 0
      • dropped_off_topic integer value at least 0
      • dropped_unsure integer value at least 0
      • shortlisted integer value at least 0
      • analysed integer value at least 0
      • updated_at string required
  • error object The same problem, nested, on a failed Run's body.

400 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/invalid_request",
  "title": "Invalid request",
  "status": 400,
  "code": "invalid_request",
  "detail": "`estimate` must be `true` or `false`.",
  "retryable": false,
  "action": "Fix the field named in `detail`, then send the corrected request."
}

401 Unauthorized

missing_authorization, invalid_key, key_revoked, key_expired or invalid_token.

Codes: missing_authorization, invalid_key, key_revoked, key_expired, invalid_token. The problem body and every code are on Errors.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose. retryable and action say whether to retry and what to do next.

  • type string required
  • title string required
  • status integer required
  • code string required one of missing_authorization, invalid_key, key_revoked, key_expired, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, key_scope_insufficient, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, focus_unsupported_kind, not_found, comment_not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, max_credits_exceeded, key_spend_cap_exceeded, rate_limit_exceeded, concurrency_limit_exceeded, tracker_limit_exceeded, webhook_limit_exceeded, webhook_rotation_in_progress, collection_limit_exceeded, collection_name_taken, collection_kind_mismatch, media_unavailable, vendor_error, source_unavailable, service_unavailable, internal_error Stable machine-readable code.
  • detail string
  • errors array of object On invalid_request from a field that failed validation: one entry per problem, so you can find the field without parsing detail. Absent when no single field is at fault, e.g. a body that is not JSON.
    • path string required Dotted path of the field to fix, e.g. collection_ids.1 or cursor. Empty for an issue with the request body as a whole.
    • message string required What is wrong with that field.
  • request_id string The request this problem answers, the same as its X-Request-Id header. Quote it to support.
  • retryable boolean required Whether sending the same request again, after any wait named here, can succeed: true for a rate or concurrency limit, an upstream outage, an internal error or a Run not yet settled; false when the request must change or a person must act. Fixed per code.
  • action string required The next step, in one sentence.
  • remedy string What to do next, as the code's error reference page says it; fuller than action. On every problem a request answers with; a per-item error inside a result may omit it.
  • retry_after_seconds integer value at least 0 Seconds to wait before retrying; the same as the Retry-After header. On rate_limit_exceeded, concurrency_limit_exceeded, source_unavailable and service_unavailable.
  • expired_at string When the key expired. On key_expired.
  • resets_at string When the request window (rate_limit_exceeded) or the key's month (key_spend_cap_exceeded) resets.
  • limit integer The limit that was hit, on the *_limit_exceeded codes.
  • running integer Runs in flight. On concurrency_limit_exceeded.
  • active integer Active Trackers or webhook endpoints. On tracker_limit_exceeded and webhook_limit_exceeded.
  • requested integer Trackers the request would resume. On tracker_limit_exceeded from a Collection action.
  • count integer Collections held. On collection_limit_exceeded.
  • balance_credits integer The Balance, in Credits. On insufficient_balance.
  • required_credits integer What the call needs, in Credits (the worst case where quoted). On insufficient_balance.
  • max_credits integer The cap the call sent. On max_credits_exceeded.
  • estimate_credits integer The call's worst-case quote, in Credits. On max_credits_exceeded and key_spend_cap_exceeded.
  • cap_credits integer The key's monthly cap. On key_spend_cap_exceeded.
  • spent_credits integer The key's Charges this UTC month. On key_spend_cap_exceeded.
  • reserved_credits integer What the key's Runs in flight hold. On key_spend_cap_exceeded.
  • endpoints array of string The sources that could not answer. On source_unavailable.
  • endpoint string The source that could not answer. On source_unavailable.
  • candidates array of object The advertisers that carry the name, to ask again with. On advertiser_ambiguous.
  • supported_kinds array of string The kinds that are accepted. On kind_deprecated and focus_unsupported_kind.
  • duration_seconds number The video's length. On video_too_long.
  • max_duration_seconds number The longest video accepted. On video_too_long.
  • overlap_expires_at string When the previous secret stops working. On webhook_rotation_in_progress.
  • scope string always read_only The key's scope. On key_scope_insufficient.
  • required string always full The scope the call needs. On key_scope_insufficient.
  • collection_id string The Collection that already has the name. On collection_name_taken.
  • collection_kind string The Collection's kind. On collection_kind_mismatch.
  • kind string The kind that was offered. On collection_kind_mismatch.
  • run_id string The Run the Idempotency-Key already belongs to. On idempotency_conflict.
  • reason string A short machine-readable reason, where a code has several.
  • reference_id string Our reference for an unexpected failure, the same as request_id; quote it when reporting it.
  • run object The Run, on a failed Run's body, so its id is kept.
    • id string required
    • kind string required What was run, e.g. video_lookup.
    • status string required one of running, completed, partial, failed partial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
    • created_at string required RFC 3339.
    • completed_at string required nullable Null while the Run is still running.
    • charge_credits integer required What this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
    • list_price_credits integer required The full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
    • cached boolean required True when a stored result answered without a fresh fetch.
    • progress object What a running Research has done so far, refreshed as it works: its stage and the counts known by then, such as analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
      • stage string required one of keywords, searching, reading_creators, filtering, analysing, writing_digest
      • keywords integer value at least 0
      • creators integer value at least 0
      • creators_read integer value at least 0
      • searches integer value at least 0
      • found integer value at least 0
      • judged integer value at least 0
      • kept integer value at least 0
      • dropped_off_topic integer value at least 0
      • dropped_unsure integer value at least 0
      • shortlisted integer value at least 0
      • analysed integer value at least 0
      • updated_at string required
  • error object The same problem, nested, on a failed Run's body.

401 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/invalid_key",
  "title": "Invalid key",
  "status": 401,
  "code": "invalid_key",
  "detail": "That API key does not exist. Keys look like `sk_live_...` and are created in the console.",
  "retryable": false,
  "action": "Check the whole key was copied, or create a new key in the console."
}

402 Payment Required

insufficient_balance — the Balance cannot cover the quoted price (the worst case for Research and enriched search). No Run is created and nothing is charged. A multi-item Run whose Balance runs short later charges its completed items up to the Balance and ends partial.

Code: insufficient_balance. The problem body and every code are on Errors.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose. retryable and action say whether to retry and what to do next.

  • type string required
  • title string required
  • status integer required
  • code string required one of missing_authorization, invalid_key, key_revoked, key_expired, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, key_scope_insufficient, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, focus_unsupported_kind, not_found, comment_not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, max_credits_exceeded, key_spend_cap_exceeded, rate_limit_exceeded, concurrency_limit_exceeded, tracker_limit_exceeded, webhook_limit_exceeded, webhook_rotation_in_progress, collection_limit_exceeded, collection_name_taken, collection_kind_mismatch, media_unavailable, vendor_error, source_unavailable, service_unavailable, internal_error Stable machine-readable code.
  • detail string
  • errors array of object On invalid_request from a field that failed validation: one entry per problem, so you can find the field without parsing detail. Absent when no single field is at fault, e.g. a body that is not JSON.
    • path string required Dotted path of the field to fix, e.g. collection_ids.1 or cursor. Empty for an issue with the request body as a whole.
    • message string required What is wrong with that field.
  • request_id string The request this problem answers, the same as its X-Request-Id header. Quote it to support.
  • retryable boolean required Whether sending the same request again, after any wait named here, can succeed: true for a rate or concurrency limit, an upstream outage, an internal error or a Run not yet settled; false when the request must change or a person must act. Fixed per code.
  • action string required The next step, in one sentence.
  • remedy string What to do next, as the code's error reference page says it; fuller than action. On every problem a request answers with; a per-item error inside a result may omit it.
  • retry_after_seconds integer value at least 0 Seconds to wait before retrying; the same as the Retry-After header. On rate_limit_exceeded, concurrency_limit_exceeded, source_unavailable and service_unavailable.
  • expired_at string When the key expired. On key_expired.
  • resets_at string When the request window (rate_limit_exceeded) or the key's month (key_spend_cap_exceeded) resets.
  • limit integer The limit that was hit, on the *_limit_exceeded codes.
  • running integer Runs in flight. On concurrency_limit_exceeded.
  • active integer Active Trackers or webhook endpoints. On tracker_limit_exceeded and webhook_limit_exceeded.
  • requested integer Trackers the request would resume. On tracker_limit_exceeded from a Collection action.
  • count integer Collections held. On collection_limit_exceeded.
  • balance_credits integer The Balance, in Credits. On insufficient_balance.
  • required_credits integer What the call needs, in Credits (the worst case where quoted). On insufficient_balance.
  • max_credits integer The cap the call sent. On max_credits_exceeded.
  • estimate_credits integer The call's worst-case quote, in Credits. On max_credits_exceeded and key_spend_cap_exceeded.
  • cap_credits integer The key's monthly cap. On key_spend_cap_exceeded.
  • spent_credits integer The key's Charges this UTC month. On key_spend_cap_exceeded.
  • reserved_credits integer What the key's Runs in flight hold. On key_spend_cap_exceeded.
  • endpoints array of string The sources that could not answer. On source_unavailable.
  • endpoint string The source that could not answer. On source_unavailable.
  • candidates array of object The advertisers that carry the name, to ask again with. On advertiser_ambiguous.
  • supported_kinds array of string The kinds that are accepted. On kind_deprecated and focus_unsupported_kind.
  • duration_seconds number The video's length. On video_too_long.
  • max_duration_seconds number The longest video accepted. On video_too_long.
  • overlap_expires_at string When the previous secret stops working. On webhook_rotation_in_progress.
  • scope string always read_only The key's scope. On key_scope_insufficient.
  • required string always full The scope the call needs. On key_scope_insufficient.
  • collection_id string The Collection that already has the name. On collection_name_taken.
  • collection_kind string The Collection's kind. On collection_kind_mismatch.
  • kind string The kind that was offered. On collection_kind_mismatch.
  • run_id string The Run the Idempotency-Key already belongs to. On idempotency_conflict.
  • reason string A short machine-readable reason, where a code has several.
  • reference_id string Our reference for an unexpected failure, the same as request_id; quote it when reporting it.
  • run object The Run, on a failed Run's body, so its id is kept.
    • id string required
    • kind string required What was run, e.g. video_lookup.
    • status string required one of running, completed, partial, failed partial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
    • created_at string required RFC 3339.
    • completed_at string required nullable Null while the Run is still running.
    • charge_credits integer required What this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
    • list_price_credits integer required The full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
    • cached boolean required True when a stored result answered without a fresh fetch.
    • progress object What a running Research has done so far, refreshed as it works: its stage and the counts known by then, such as analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
      • stage string required one of keywords, searching, reading_creators, filtering, analysing, writing_digest
      • keywords integer value at least 0
      • creators integer value at least 0
      • creators_read integer value at least 0
      • searches integer value at least 0
      • found integer value at least 0
      • judged integer value at least 0
      • kept integer value at least 0
      • dropped_off_topic integer value at least 0
      • dropped_unsure integer value at least 0
      • shortlisted integer value at least 0
      • analysed integer value at least 0
      • updated_at string required
  • error object The same problem, nested, on a failed Run's body.

402 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/insufficient_balance",
  "title": "Insufficient balance",
  "status": 402,
  "code": "insufficient_balance",
  "detail": "Your balance is 0 Credits and this operation needs 1018 Credits. Nothing was charged.",
  "retryable": false,
  "action": "Tell the Customer to top up the Balance, then repeat the same request.",
  "balance_credits": 0,
  "required_credits": 1018
}

409 Conflict

idempotency_conflict — the same Idempotency-Key with a different payload.

Code: idempotency_conflict. The problem body and every code are on Errors.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose. retryable and action say whether to retry and what to do next.

  • type string required
  • title string required
  • status integer required
  • code string required one of missing_authorization, invalid_key, key_revoked, key_expired, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, key_scope_insufficient, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, focus_unsupported_kind, not_found, comment_not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, max_credits_exceeded, key_spend_cap_exceeded, rate_limit_exceeded, concurrency_limit_exceeded, tracker_limit_exceeded, webhook_limit_exceeded, webhook_rotation_in_progress, collection_limit_exceeded, collection_name_taken, collection_kind_mismatch, media_unavailable, vendor_error, source_unavailable, service_unavailable, internal_error Stable machine-readable code.
  • detail string
  • errors array of object On invalid_request from a field that failed validation: one entry per problem, so you can find the field without parsing detail. Absent when no single field is at fault, e.g. a body that is not JSON.
    • path string required Dotted path of the field to fix, e.g. collection_ids.1 or cursor. Empty for an issue with the request body as a whole.
    • message string required What is wrong with that field.
  • request_id string The request this problem answers, the same as its X-Request-Id header. Quote it to support.
  • retryable boolean required Whether sending the same request again, after any wait named here, can succeed: true for a rate or concurrency limit, an upstream outage, an internal error or a Run not yet settled; false when the request must change or a person must act. Fixed per code.
  • action string required The next step, in one sentence.
  • remedy string What to do next, as the code's error reference page says it; fuller than action. On every problem a request answers with; a per-item error inside a result may omit it.
  • retry_after_seconds integer value at least 0 Seconds to wait before retrying; the same as the Retry-After header. On rate_limit_exceeded, concurrency_limit_exceeded, source_unavailable and service_unavailable.
  • expired_at string When the key expired. On key_expired.
  • resets_at string When the request window (rate_limit_exceeded) or the key's month (key_spend_cap_exceeded) resets.
  • limit integer The limit that was hit, on the *_limit_exceeded codes.
  • running integer Runs in flight. On concurrency_limit_exceeded.
  • active integer Active Trackers or webhook endpoints. On tracker_limit_exceeded and webhook_limit_exceeded.
  • requested integer Trackers the request would resume. On tracker_limit_exceeded from a Collection action.
  • count integer Collections held. On collection_limit_exceeded.
  • balance_credits integer The Balance, in Credits. On insufficient_balance.
  • required_credits integer What the call needs, in Credits (the worst case where quoted). On insufficient_balance.
  • max_credits integer The cap the call sent. On max_credits_exceeded.
  • estimate_credits integer The call's worst-case quote, in Credits. On max_credits_exceeded and key_spend_cap_exceeded.
  • cap_credits integer The key's monthly cap. On key_spend_cap_exceeded.
  • spent_credits integer The key's Charges this UTC month. On key_spend_cap_exceeded.
  • reserved_credits integer What the key's Runs in flight hold. On key_spend_cap_exceeded.
  • endpoints array of string The sources that could not answer. On source_unavailable.
  • endpoint string The source that could not answer. On source_unavailable.
  • candidates array of object The advertisers that carry the name, to ask again with. On advertiser_ambiguous.
  • supported_kinds array of string The kinds that are accepted. On kind_deprecated and focus_unsupported_kind.
  • duration_seconds number The video's length. On video_too_long.
  • max_duration_seconds number The longest video accepted. On video_too_long.
  • overlap_expires_at string When the previous secret stops working. On webhook_rotation_in_progress.
  • scope string always read_only The key's scope. On key_scope_insufficient.
  • required string always full The scope the call needs. On key_scope_insufficient.
  • collection_id string The Collection that already has the name. On collection_name_taken.
  • collection_kind string The Collection's kind. On collection_kind_mismatch.
  • kind string The kind that was offered. On collection_kind_mismatch.
  • run_id string The Run the Idempotency-Key already belongs to. On idempotency_conflict.
  • reason string A short machine-readable reason, where a code has several.
  • reference_id string Our reference for an unexpected failure, the same as request_id; quote it when reporting it.
  • run object The Run, on a failed Run's body, so its id is kept.
    • id string required
    • kind string required What was run, e.g. video_lookup.
    • status string required one of running, completed, partial, failed partial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
    • created_at string required RFC 3339.
    • completed_at string required nullable Null while the Run is still running.
    • charge_credits integer required What this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
    • list_price_credits integer required The full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
    • cached boolean required True when a stored result answered without a fresh fetch.
    • progress object What a running Research has done so far, refreshed as it works: its stage and the counts known by then, such as analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
      • stage string required one of keywords, searching, reading_creators, filtering, analysing, writing_digest
      • keywords integer value at least 0
      • creators integer value at least 0
      • creators_read integer value at least 0
      • searches integer value at least 0
      • found integer value at least 0
      • judged integer value at least 0
      • kept integer value at least 0
      • dropped_off_topic integer value at least 0
      • dropped_unsure integer value at least 0
      • shortlisted integer value at least 0
      • analysed integer value at least 0
      • updated_at string required
  • error object The same problem, nested, on a failed Run's body.

409 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/idempotency_conflict",
  "title": "Idempotency conflict",
  "status": 409,
  "code": "idempotency_conflict",
  "detail": "This Idempotency-Key was used with a different payload.",
  "retryable": false,
  "action": "Resend the original payload with this key, or use a new key for the new payload.",
  "run_id": "run_8f2c1ad04b"
}

429 Too Many Requests

rate_limit_exceeded or concurrency_limit_exceeded, with Retry-After.

Codes: rate_limit_exceeded, concurrency_limit_exceeded. The problem body and every code are on Errors.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose. retryable and action say whether to retry and what to do next.

  • type string required
  • title string required
  • status integer required
  • code string required one of missing_authorization, invalid_key, key_revoked, key_expired, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, key_scope_insufficient, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, focus_unsupported_kind, not_found, comment_not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, max_credits_exceeded, key_spend_cap_exceeded, rate_limit_exceeded, concurrency_limit_exceeded, tracker_limit_exceeded, webhook_limit_exceeded, webhook_rotation_in_progress, collection_limit_exceeded, collection_name_taken, collection_kind_mismatch, media_unavailable, vendor_error, source_unavailable, service_unavailable, internal_error Stable machine-readable code.
  • detail string
  • errors array of object On invalid_request from a field that failed validation: one entry per problem, so you can find the field without parsing detail. Absent when no single field is at fault, e.g. a body that is not JSON.
    • path string required Dotted path of the field to fix, e.g. collection_ids.1 or cursor. Empty for an issue with the request body as a whole.
    • message string required What is wrong with that field.
  • request_id string The request this problem answers, the same as its X-Request-Id header. Quote it to support.
  • retryable boolean required Whether sending the same request again, after any wait named here, can succeed: true for a rate or concurrency limit, an upstream outage, an internal error or a Run not yet settled; false when the request must change or a person must act. Fixed per code.
  • action string required The next step, in one sentence.
  • remedy string What to do next, as the code's error reference page says it; fuller than action. On every problem a request answers with; a per-item error inside a result may omit it.
  • retry_after_seconds integer value at least 0 Seconds to wait before retrying; the same as the Retry-After header. On rate_limit_exceeded, concurrency_limit_exceeded, source_unavailable and service_unavailable.
  • expired_at string When the key expired. On key_expired.
  • resets_at string When the request window (rate_limit_exceeded) or the key's month (key_spend_cap_exceeded) resets.
  • limit integer The limit that was hit, on the *_limit_exceeded codes.
  • running integer Runs in flight. On concurrency_limit_exceeded.
  • active integer Active Trackers or webhook endpoints. On tracker_limit_exceeded and webhook_limit_exceeded.
  • requested integer Trackers the request would resume. On tracker_limit_exceeded from a Collection action.
  • count integer Collections held. On collection_limit_exceeded.
  • balance_credits integer The Balance, in Credits. On insufficient_balance.
  • required_credits integer What the call needs, in Credits (the worst case where quoted). On insufficient_balance.
  • max_credits integer The cap the call sent. On max_credits_exceeded.
  • estimate_credits integer The call's worst-case quote, in Credits. On max_credits_exceeded and key_spend_cap_exceeded.
  • cap_credits integer The key's monthly cap. On key_spend_cap_exceeded.
  • spent_credits integer The key's Charges this UTC month. On key_spend_cap_exceeded.
  • reserved_credits integer What the key's Runs in flight hold. On key_spend_cap_exceeded.
  • endpoints array of string The sources that could not answer. On source_unavailable.
  • endpoint string The source that could not answer. On source_unavailable.
  • candidates array of object The advertisers that carry the name, to ask again with. On advertiser_ambiguous.
  • supported_kinds array of string The kinds that are accepted. On kind_deprecated and focus_unsupported_kind.
  • duration_seconds number The video's length. On video_too_long.
  • max_duration_seconds number The longest video accepted. On video_too_long.
  • overlap_expires_at string When the previous secret stops working. On webhook_rotation_in_progress.
  • scope string always read_only The key's scope. On key_scope_insufficient.
  • required string always full The scope the call needs. On key_scope_insufficient.
  • collection_id string The Collection that already has the name. On collection_name_taken.
  • collection_kind string The Collection's kind. On collection_kind_mismatch.
  • kind string The kind that was offered. On collection_kind_mismatch.
  • run_id string The Run the Idempotency-Key already belongs to. On idempotency_conflict.
  • reason string A short machine-readable reason, where a code has several.
  • reference_id string Our reference for an unexpected failure, the same as request_id; quote it when reporting it.
  • run object The Run, on a failed Run's body, so its id is kept.
    • id string required
    • kind string required What was run, e.g. video_lookup.
    • status string required one of running, completed, partial, failed partial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
    • created_at string required RFC 3339.
    • completed_at string required nullable Null while the Run is still running.
    • charge_credits integer required What this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
    • list_price_credits integer required The full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
    • cached boolean required True when a stored result answered without a fresh fetch.
    • progress object What a running Research has done so far, refreshed as it works: its stage and the counts known by then, such as analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
      • stage string required one of keywords, searching, reading_creators, filtering, analysing, writing_digest
      • keywords integer value at least 0
      • creators integer value at least 0
      • creators_read integer value at least 0
      • searches integer value at least 0
      • found integer value at least 0
      • judged integer value at least 0
      • kept integer value at least 0
      • dropped_off_topic integer value at least 0
      • dropped_unsure integer value at least 0
      • shortlisted integer value at least 0
      • analysed integer value at least 0
      • updated_at string required
  • error object The same problem, nested, on a failed Run's body.

429 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/rate_limit_exceeded",
  "title": "Rate limit exceeded",
  "status": 429,
  "code": "rate_limit_exceeded",
  "detail": "60 requests per minute per key. Retry after the number of seconds in `Retry-After`.",
  "retryable": true,
  "action": "Wait `retry_after_seconds`, then retry the same request.",
  "limit": 60,
  "retry_after_seconds": 12,
  "resets_at": "2026-09-08T09:15:00.000Z"
}

502 Bad Gateway

A Run that opened and then failed is answered as application/problem+json with its problem's status — vendor_error here, not_found as 404 — and the Run envelope alongside, so the Run id is kept. A failed Run is never charged.

Code: vendor_error. The problem body and every code are on Errors.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose. retryable and action say whether to retry and what to do next.

  • type string required
  • title string required
  • status integer required
  • code string required one of missing_authorization, invalid_key, key_revoked, key_expired, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, key_scope_insufficient, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, focus_unsupported_kind, not_found, comment_not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, max_credits_exceeded, key_spend_cap_exceeded, rate_limit_exceeded, concurrency_limit_exceeded, tracker_limit_exceeded, webhook_limit_exceeded, webhook_rotation_in_progress, collection_limit_exceeded, collection_name_taken, collection_kind_mismatch, media_unavailable, vendor_error, source_unavailable, service_unavailable, internal_error Stable machine-readable code.
  • detail string
  • errors array of object On invalid_request from a field that failed validation: one entry per problem, so you can find the field without parsing detail. Absent when no single field is at fault, e.g. a body that is not JSON.
    • path string required Dotted path of the field to fix, e.g. collection_ids.1 or cursor. Empty for an issue with the request body as a whole.
    • message string required What is wrong with that field.
  • request_id string The request this problem answers, the same as its X-Request-Id header. Quote it to support.
  • retryable boolean required Whether sending the same request again, after any wait named here, can succeed: true for a rate or concurrency limit, an upstream outage, an internal error or a Run not yet settled; false when the request must change or a person must act. Fixed per code.
  • action string required The next step, in one sentence.
  • remedy string What to do next, as the code's error reference page says it; fuller than action. On every problem a request answers with; a per-item error inside a result may omit it.
  • retry_after_seconds integer value at least 0 Seconds to wait before retrying; the same as the Retry-After header. On rate_limit_exceeded, concurrency_limit_exceeded, source_unavailable and service_unavailable.
  • expired_at string When the key expired. On key_expired.
  • resets_at string When the request window (rate_limit_exceeded) or the key's month (key_spend_cap_exceeded) resets.
  • limit integer The limit that was hit, on the *_limit_exceeded codes.
  • running integer Runs in flight. On concurrency_limit_exceeded.
  • active integer Active Trackers or webhook endpoints. On tracker_limit_exceeded and webhook_limit_exceeded.
  • requested integer Trackers the request would resume. On tracker_limit_exceeded from a Collection action.
  • count integer Collections held. On collection_limit_exceeded.
  • balance_credits integer The Balance, in Credits. On insufficient_balance.
  • required_credits integer What the call needs, in Credits (the worst case where quoted). On insufficient_balance.
  • max_credits integer The cap the call sent. On max_credits_exceeded.
  • estimate_credits integer The call's worst-case quote, in Credits. On max_credits_exceeded and key_spend_cap_exceeded.
  • cap_credits integer The key's monthly cap. On key_spend_cap_exceeded.
  • spent_credits integer The key's Charges this UTC month. On key_spend_cap_exceeded.
  • reserved_credits integer What the key's Runs in flight hold. On key_spend_cap_exceeded.
  • endpoints array of string The sources that could not answer. On source_unavailable.
  • endpoint string The source that could not answer. On source_unavailable.
  • candidates array of object The advertisers that carry the name, to ask again with. On advertiser_ambiguous.
  • supported_kinds array of string The kinds that are accepted. On kind_deprecated and focus_unsupported_kind.
  • duration_seconds number The video's length. On video_too_long.
  • max_duration_seconds number The longest video accepted. On video_too_long.
  • overlap_expires_at string When the previous secret stops working. On webhook_rotation_in_progress.
  • scope string always read_only The key's scope. On key_scope_insufficient.
  • required string always full The scope the call needs. On key_scope_insufficient.
  • collection_id string The Collection that already has the name. On collection_name_taken.
  • collection_kind string The Collection's kind. On collection_kind_mismatch.
  • kind string The kind that was offered. On collection_kind_mismatch.
  • run_id string The Run the Idempotency-Key already belongs to. On idempotency_conflict.
  • reason string A short machine-readable reason, where a code has several.
  • reference_id string Our reference for an unexpected failure, the same as request_id; quote it when reporting it.
  • run object The Run, on a failed Run's body, so its id is kept.
    • id string required
    • kind string required What was run, e.g. video_lookup.
    • status string required one of running, completed, partial, failed partial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
    • created_at string required RFC 3339.
    • completed_at string required nullable Null while the Run is still running.
    • charge_credits integer required What this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
    • list_price_credits integer required The full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
    • cached boolean required True when a stored result answered without a fresh fetch.
    • progress object What a running Research has done so far, refreshed as it works: its stage and the counts known by then, such as analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
      • stage string required one of keywords, searching, reading_creators, filtering, analysing, writing_digest
      • keywords integer value at least 0
      • creators integer value at least 0
      • creators_read integer value at least 0
      • searches integer value at least 0
      • found integer value at least 0
      • judged integer value at least 0
      • kept integer value at least 0
      • dropped_off_topic integer value at least 0
      • dropped_unsure integer value at least 0
      • shortlisted integer value at least 0
      • analysed integer value at least 0
      • updated_at string required
  • error object The same problem, nested, on a failed Run's body.

502 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/vendor_error",
  "title": "Vendor error",
  "status": 502,
  "code": "vendor_error",
  "detail": "The upstream data provider could not be reached.",
  "retryable": true,
  "action": "Retry with a backoff; nothing was charged.",
  "run": {
    "id": "run_8f2c1ad04b",
    "kind": "research",
    "status": "failed",
    "created_at": "2026-09-08T09:14:02.418Z",
    "completed_at": "2026-09-08T09:14:04.930Z",
    "charge_credits": 0,
    "list_price_credits": 0,
    "cached": false
  }
}

503 Service Unavailable

source_unavailable: every source this Run reads failed or is switched off. The Run fails uncharged, with its envelope alongside; endpoints names the source. Wait retry_after_seconds (also sent as Retry-After) and retry rather than treating it as empty.

Code: source_unavailable. The problem body and every code are on Errors.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose. retryable and action say whether to retry and what to do next.

  • type string required
  • title string required
  • status integer required
  • code string required one of missing_authorization, invalid_key, key_revoked, key_expired, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, key_scope_insufficient, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, focus_unsupported_kind, not_found, comment_not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, max_credits_exceeded, key_spend_cap_exceeded, rate_limit_exceeded, concurrency_limit_exceeded, tracker_limit_exceeded, webhook_limit_exceeded, webhook_rotation_in_progress, collection_limit_exceeded, collection_name_taken, collection_kind_mismatch, media_unavailable, vendor_error, source_unavailable, service_unavailable, internal_error Stable machine-readable code.
  • detail string
  • errors array of object On invalid_request from a field that failed validation: one entry per problem, so you can find the field without parsing detail. Absent when no single field is at fault, e.g. a body that is not JSON.
    • path string required Dotted path of the field to fix, e.g. collection_ids.1 or cursor. Empty for an issue with the request body as a whole.
    • message string required What is wrong with that field.
  • request_id string The request this problem answers, the same as its X-Request-Id header. Quote it to support.
  • retryable boolean required Whether sending the same request again, after any wait named here, can succeed: true for a rate or concurrency limit, an upstream outage, an internal error or a Run not yet settled; false when the request must change or a person must act. Fixed per code.
  • action string required The next step, in one sentence.
  • remedy string What to do next, as the code's error reference page says it; fuller than action. On every problem a request answers with; a per-item error inside a result may omit it.
  • retry_after_seconds integer value at least 0 Seconds to wait before retrying; the same as the Retry-After header. On rate_limit_exceeded, concurrency_limit_exceeded, source_unavailable and service_unavailable.
  • expired_at string When the key expired. On key_expired.
  • resets_at string When the request window (rate_limit_exceeded) or the key's month (key_spend_cap_exceeded) resets.
  • limit integer The limit that was hit, on the *_limit_exceeded codes.
  • running integer Runs in flight. On concurrency_limit_exceeded.
  • active integer Active Trackers or webhook endpoints. On tracker_limit_exceeded and webhook_limit_exceeded.
  • requested integer Trackers the request would resume. On tracker_limit_exceeded from a Collection action.
  • count integer Collections held. On collection_limit_exceeded.
  • balance_credits integer The Balance, in Credits. On insufficient_balance.
  • required_credits integer What the call needs, in Credits (the worst case where quoted). On insufficient_balance.
  • max_credits integer The cap the call sent. On max_credits_exceeded.
  • estimate_credits integer The call's worst-case quote, in Credits. On max_credits_exceeded and key_spend_cap_exceeded.
  • cap_credits integer The key's monthly cap. On key_spend_cap_exceeded.
  • spent_credits integer The key's Charges this UTC month. On key_spend_cap_exceeded.
  • reserved_credits integer What the key's Runs in flight hold. On key_spend_cap_exceeded.
  • endpoints array of string The sources that could not answer. On source_unavailable.
  • endpoint string The source that could not answer. On source_unavailable.
  • candidates array of object The advertisers that carry the name, to ask again with. On advertiser_ambiguous.
  • supported_kinds array of string The kinds that are accepted. On kind_deprecated and focus_unsupported_kind.
  • duration_seconds number The video's length. On video_too_long.
  • max_duration_seconds number The longest video accepted. On video_too_long.
  • overlap_expires_at string When the previous secret stops working. On webhook_rotation_in_progress.
  • scope string always read_only The key's scope. On key_scope_insufficient.
  • required string always full The scope the call needs. On key_scope_insufficient.
  • collection_id string The Collection that already has the name. On collection_name_taken.
  • collection_kind string The Collection's kind. On collection_kind_mismatch.
  • kind string The kind that was offered. On collection_kind_mismatch.
  • run_id string The Run the Idempotency-Key already belongs to. On idempotency_conflict.
  • reason string A short machine-readable reason, where a code has several.
  • reference_id string Our reference for an unexpected failure, the same as request_id; quote it when reporting it.
  • run object The Run, on a failed Run's body, so its id is kept.
    • id string required
    • kind string required What was run, e.g. video_lookup.
    • status string required one of running, completed, partial, failed partial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
    • created_at string required RFC 3339.
    • completed_at string required nullable Null while the Run is still running.
    • charge_credits integer required What this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
    • list_price_credits integer required The full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
    • cached boolean required True when a stored result answered without a fresh fetch.
    • progress object What a running Research has done so far, refreshed as it works: its stage and the counts known by then, such as analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
      • stage string required one of keywords, searching, reading_creators, filtering, analysing, writing_digest
      • keywords integer value at least 0
      • creators integer value at least 0
      • creators_read integer value at least 0
      • searches integer value at least 0
      • found integer value at least 0
      • judged integer value at least 0
      • kept integer value at least 0
      • dropped_off_topic integer value at least 0
      • dropped_unsure integer value at least 0
      • shortlisted integer value at least 0
      • analysed integer value at least 0
      • updated_at string required
  • error object The same problem, nested, on a failed Run's body.

503 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/source_unavailable",
  "title": "Source unavailable",
  "status": 503,
  "code": "source_unavailable",
  "detail": "The tiktok/video source is unavailable right now.",
  "retryable": true,
  "action": "Wait `retry_after_seconds`, then retry; do not treat this as an empty result.",
  "endpoints": [
    "tiktok/video"
  ],
  "run": {
    "id": "run_8f2c1ad04b",
    "kind": "research",
    "status": "failed",
    "created_at": "2026-09-08T09:14:02.418Z",
    "completed_at": "2026-09-08T09:14:04.930Z",
    "charge_credits": 0,
    "list_price_credits": 0,
    "cached": false
  },
  "retry_after_seconds": 60
}

Request samples

Use ShortsIntel to break down what works for a set of Creators.

- videos_per_creator: 25

Tell me what it will cost before you run it, then summarise what you find.

If you don't have ShortsIntel tools, don't guess: read https://www.shortsintel.com/agents.md, follow it to connect, then retry this request.

This call creates a Run. With wait it holds the response open until the Run finishes or the wait runs out, then answers with the finished result or 202 and the running Run. Poll GET /v1/runs/{id} until it settles; re-reading a Run is free.

  • Runs: How a call becomes a Run, waiting inline, polling and free re-reads.
  • Pricing and estimates: Credits, estimates and why a cached result costs the same as a fresh one.
  • Research: How an intent becomes a digest, why a research id is a run id, and how to re-slice what you collected for free instead of paying for it twice.