Skip to content

API referenceResearch

Refresh a research's videos

POST/v1/research/{id}/refresh

Sweeps fresh metrics for the videos a research serves, so you can see which of them kept growing. Afterwards as_of=latest on any research read serves these numbers; as_of=run is untouched, byte for byte, because nothing rewrites what the research recorded. It is a run rather than a flag on the reads because it fetches every video again from its source and reads must stay free. Only TikTok videos can be refreshed today: videos on other platforms are left out of the quote, the sweep and the charge, and keep the numbers the research recorded; a research with no TikTok videos is refused with 400 unsupported_platform, and a research that serves no videos at all with 400 invalid_request, both before any run opens. One item per video, each with its own status: videos that fail are not charged, some failing makes the run partial, all failing makes it failed and charges nothing. If the Balance runs short by the time the sweep settles, the videos that came back are charged in order up to the Balance and the rest fail with insufficient_balance, leaving the run partial. A retried request with the same Idempotency-Key returns the original run and is not charged again; send a new key for a later sweep. The snapshots are stored, so every later call about those videos — yours or anyone's — starts from them.

Open in Playground(no API Key needed)

Price

3 credits per video that comes back.

Supports estimate=true: 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
idpathstringRequired—Research id — the id of the Run that collected it.
Idempotency-KeyheaderstringOptional—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.
waitqueryintegermin 0; max 120Optional30Seconds to hold the response open before handing back a running Run to poll. Default 30, max 120. A POST may send it in the body instead; given in both places with different values it is a 400.
estimatequerybooleanOptional—true returns { estimate_credits, cached } computed from what is already stored, and creates no Run. Nothing is charged. Only true or false; anything else is a 400. A POST may send it in the body instead; given in both places with different values it is a 400.

Responses

200 OK

The sweep finished inside the wait budget: { run, result }. The example is a partial run — two of the fifty videos have been deleted since the research ran, so forty-eight were swept and charged for. With estimate=true, { estimate_credits, cached, videos, per_video_credits, max_estimate_credits, note } instead: videos is how many will be swept, max_estimate_credits equals estimate_credits because a video that fails is not charged, and note says so — and, when some of the research's videos are on a platform that cannot be refreshed yet, how many are left out.

any of 2 shapes

  • Option 1object
    • runobjectrequiredEvery charged operation creates a Run. The envelope is identical whether the result came back inline or was polled.
      • idstringrequired
      • kindstringrequiredWhat was run, e.g. video_lookup.
      • statusstringrequiredone of running, completed, partial, failedpartial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
      • created_atstringrequiredRFC 3339.
      • completed_atstringrequirednullableNull while the Run is still running.
      • charge_creditsintegerrequiredWhat this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
      • list_price_creditsintegerrequiredThe full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
      • cachedbooleanrequiredTrue when a stored result answered without paying the vendor.
      • progressobjectWhat a running Research has done so far, refreshed as it works: stage (keywords, searching, filtering, analysing, writing_digest) and the counts known by then — keywords, found, kept, dropped_off_topic, and analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
        • stagestringrequiredone of keywords, searching, filtering, analysing, writing_digest
        • keywordsintegervalue at least 0
        • searchesintegervalue at least 0
        • foundintegervalue at least 0
        • judgedintegervalue at least 0
        • keptintegervalue at least 0
        • dropped_off_topicintegervalue at least 0
        • dropped_unsureintegervalue at least 0
        • shortlistedintegervalue at least 0
        • analysedintegervalue at least 0
        • updated_atstringrequired
    • resultobjectrequiredWhat a refresh swept. Frozen reads are unchanged by it; as_of=latest serves the new snapshots.
      • research_idstringrequiredThe research whose videos were swept.
      • requestedintegerrequired
      • refreshedintegerrequiredVideos we fetched fresh numbers for, and the only ones charged for.
      • failedintegerrequired
      • per_video_creditsintegerrequired
      • notestringrequired
  • Option 2objectReturned 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_creditsintegerrequiredWhat the call would be charged, in Credits.
    • cachedbooleanrequiredWhether a stored result can already answer. It does not change the price.

200 · The sweep finished inside the wait budget: `{ run, result }`. The example is a `partial` run — two of the fifty videos have been deleted since the research ran, so forty-eight were swept and charged for. With `estimate=true`, `{ estimate_credits, cached, videos, per_video_credits, max_estimate_credits, note }` instead: `videos` is how many will be swept, `max_estimate_credits` equals `estimate_credits` because a video that fails is not charged, and `note` says so — and, when some of the research's videos are on a platform that cannot be refreshed yet, how many are left out.

{
  "run": {
    "id": "run_8f2c1ad04b",
    "kind": "research_refresh",
    "status": "partial",
    "created_at": "2026-09-08T09:14:02.418Z",
    "completed_at": "2026-09-08T09:14:04.930Z",
    "charge_credits": 144,
    "list_price_credits": 150,
    "cached": false
  },
  "result": {
    "research_id": "run_c07a41bb92",
    "requested": 50,
    "refreshed": 48,
    "failed": 2,
    "per_video_credits": 3,
    "note": "Frozen reads are unchanged. `as_of=latest` now serves these snapshots."
  }
}

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

{
  "estimate_credits": 150,
  "cached": false,
  "videos": 50,
  "per_video_credits": 3,
  "max_estimate_credits": 150,
  "note": "A video we cannot fetch is not charged, so the final charge is at or below this quote."
}

202 Accepted

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

object

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

  • runobjectrequiredEvery charged operation creates a Run. The envelope is identical whether the result came back inline or was polled.
    • idstringrequired
    • kindstringrequiredWhat was run, e.g. video_lookup.
    • statusstringrequiredone of running, completed, partial, failedpartial keeps the completed items and charges for them, up to what the Balance covers; failed charges nothing.
    • created_atstringrequiredRFC 3339.
    • completed_atstringrequirednullableNull while the Run is still running.
    • charge_creditsintegerrequiredWhat this Run actually cost, in Credits. A stored answer costs the same as a fresh one.
    • list_price_creditsintegerrequiredThe full price of the work asked for, in Credits. Equal to charge_credits unless the Run charged for only part of it.
    • cachedbooleanrequiredTrue when a stored result answered without paying the vendor.
    • progressobjectWhat a running Research has done so far, refreshed as it works: stage (keywords, searching, filtering, analysing, writing_digest) and the counts known by then — keywords, found, kept, dropped_off_topic, and analysed of shortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.
      • stagestringrequiredone of keywords, searching, filtering, analysing, writing_digest
      • keywordsintegervalue at least 0
      • searchesintegervalue at least 0
      • foundintegervalue at least 0
      • judgedintegervalue at least 0
      • keptintegervalue at least 0
      • dropped_off_topicintegervalue at least 0
      • dropped_unsureintegervalue at least 0
      • shortlistedintegervalue at least 0
      • analysedintegervalue at least 0
      • updated_atstringrequired

202 · Example

{
  "run": {
    "id": "run_8f2c1ad04b",
    "kind": "research_refresh",
    "status": "running",
    "created_at": "2026-09-08T09:14:02.418Z",
    "completed_at": null,
    "charge_credits": 0,
    "list_price_credits": 0,
    "cached": false
  }
}

400 Bad Request

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

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose.

  • typestringrequired
  • titlestringrequired
  • statusintegerrequired
  • codestringrequiredone of missing_authorization, invalid_key, key_revoked, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, 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_errorStable machine-readable code.
  • detailstring

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`."
}

401 Unauthorized

missing_authorization, invalid_key, key_revoked or invalid_token.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose.

  • typestringrequired
  • titlestringrequired
  • statusintegerrequired
  • codestringrequiredone of missing_authorization, invalid_key, key_revoked, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, 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_errorStable machine-readable code.
  • detailstring

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."
}

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.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose.

  • typestringrequired
  • titlestringrequired
  • statusintegerrequired
  • codestringrequiredone of missing_authorization, invalid_key, key_revoked, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, 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_errorStable machine-readable code.
  • detailstring

402 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/insufficient_balance",
  "title": "Insufficient balance",
  "status": 402,
  "code": "insufficient_balance",
  "detail": "Your balance does not cover this operation. Top up in the console.",
  "balance_credits": 0,
  "required_credits": 150
}

404 Not Found

not_found.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose.

  • typestringrequired
  • titlestringrequired
  • statusintegerrequired
  • codestringrequiredone of missing_authorization, invalid_key, key_revoked, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, 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_errorStable machine-readable code.
  • detailstring

404 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/not_found",
  "title": "Not found",
  "status": 404,
  "code": "not_found",
  "detail": "No research with that id for this Customer."
}

409 Conflict

run_not_ready — the research is still running, or failed with nothing to serve. If it is still running, poll GET /v1/runs/{id} and refresh once it settles; a failed research never becomes readable. Also idempotency_conflict — the same Idempotency-Key sent for a different research.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose.

  • typestringrequired
  • titlestringrequired
  • statusintegerrequired
  • codestringrequiredone of missing_authorization, invalid_key, key_revoked, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, 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_errorStable machine-readable code.
  • detailstring

409 · Example

{
  "type": "https://www.shortsintel.com/docs/reference/errors/run_not_ready",
  "title": "Run not ready",
  "status": 409,
  "code": "run_not_ready",
  "detail": "Research `run_c07a41bb92` is still running. Poll GET /v1/runs/run_c07a41bb92 until it reaches a terminal status."
}

429 Too Many Requests

rate_limit_exceeded or concurrency_limit_exceeded, with Retry-After.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose.

  • typestringrequired
  • titlestringrequired
  • statusintegerrequired
  • codestringrequiredone of missing_authorization, invalid_key, key_revoked, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, 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_errorStable machine-readable code.
  • detailstring

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`.",
  "limit": 60
}

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.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose.

  • typestringrequired
  • titlestringrequired
  • statusintegerrequired
  • codestringrequiredone of missing_authorization, invalid_key, key_revoked, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, 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_errorStable machine-readable code.
  • detailstring

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.",
  "run": {
    "id": "run_8f2c1ad04b",
    "kind": "research_refresh",
    "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. Retry later rather than treating it as empty.

object

RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose.

  • typestringrequired
  • titlestringrequired
  • statusintegerrequired
  • codestringrequiredone of missing_authorization, invalid_key, key_revoked, invalid_token, organization_not_selected, organization_access_revoked, connection_revoked, forbidden, invalid_request, unsupported_platform, unsupported_kind, kind_deprecated, not_found, video_too_long, idempotency_conflict, run_not_ready, advertiser_ambiguous, insufficient_balance, 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_errorStable machine-readable code.
  • detailstring

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.",
  "endpoints": [
    "tiktok/video"
  ],
  "run": {
    "id": "run_8f2c1ad04b",
    "kind": "research_refresh",
    "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
  }
}

Request samples

curl -X POST "https://www.shortsintel.com/v1/research/id_example/refresh?wait=30" \
  -H "Authorization: Bearer sk_live_YOUR_KEY"

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.