Search ad libraries
/v1/ads/searchThe Meta or TikTok ad library, by keyword or by advertiser — exactly one of query or advertiser. On Meta, advertiser is a Facebook Page id, a Page URL or a name; a name several Pages carry fails with 409 advertiser_ambiguous and candidates (page_id, name, page_url, instagram, ad_count) instead of a guess, and nothing is charged; an estimate answers the same 409 when two or more stored Advertisers carry the name, without asking the library. An advertiser search by Page id or Page URL whose advertiser had a complete observation in the last 6 hours (a status: all search with no other filter read to the end, or a fresh GET /v1/advertisers/{page_id}) is served from what is stored at the same per-Ad price, unless it sets country; advertiser searches say cached and as_of. Meta takes Meta's filters (country, omitted for every country; status, running by default; kind, commercial by default; media_type; placements; a start-date range) and a limit up to 500, read across as many library pages as it takes; follow next_cursor for more. Every Meta Ad returned is stored with its Advertiser and a Snapshot of its public state, and is one item of the Run. A keyword search is always fetched live. If the library fails part-way, the Run is partial, charged only for the Ads delivered, and incomplete says why; next_cursor resumes where it stopped. If it cannot be reached at all the Run fails with source_unavailable and nothing is charged, and an estimate answers source_unavailable too. analyze: true adds Ad analysis to the first 50 Ads: video Ads get the full video set (transcript, hook, persuasion, tone, visual, safety), image and carousel Ads the image set (copy angle, offer, CTA, visual format, topics, sentiment), read from our archived media with the ad copy as context. Analysis is computed once per Ad and version and reused by every later Run, charged the same as when computed; every Ad carries the analysis already stored for it either way. The passes run after the Ads are read, so expect a 202 and poll the Run; an Ad whose analysis fails is not charged at all and makes the Run partial, and a Run where no Ad got an analysis fails and charges nothing. The TikTok library is one page per call, global, not stored, and refuses the Meta-only filters (and analyze) rather than ignoring them. Ads are trimmed: never the raw library payload.
Open in Playground(no API Key needed)
Price
Meta: 1 credit per Ad delivered, the same when served from a recent advertiser observation, plus 20 credits per Ad analysed with analyze, computed or already stored; the estimate quotes limit Ads, all analysed up to the cap with analyze. TikTok: 3 credits per page.
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
| Name | In | Type | Required | Default | Description |
|---|---|---|---|---|---|
Idempotency-Key | header | string | 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
librarystringrequiredone ofmeta,tiktokquerystringlength at least 1advertiserstringlength at least 1countrystringlength 2 to 2Two-letter country code; omitted searches every country. Meta only; the TikTok library is global and refuses it.statusstringone ofactive,inactive,allRunning (active, the default), stopped (inactive) orall. Meta only; the TikTok library refuses it.kindstringone ofcommercial,political,issue,allcommercial(the default),political,issueorall. Meta only; the TikTok library refuses it.media_typestringone ofvideo,image,carouselOnly Ads of this format; omitted means every format. Meta only; the TikTok library refuses it.placementsarray of stringitems 1 to 4Only Ads placed on at least one of these. Meta only; the TikTok library refuses it.started_afterstringISO date or timestamp; Ads that started on or after it. Meta only; the TikTok library refuses it.started_beforestringISO date or timestamp; Ads that started before it. Meta only; the TikTok library refuses it.limitintegervalue 1 to 500Meta: default 50, at most 500, fetched across as many library pages as it takes. TikTok: default 25, at most 30.cursorstringlength at least 1order_bystringone ofrelevance,winner,days_running,start_daterelevance(the default) keeps the library's order;winnersorts by winner Score,days_runningby days run,start_datenewest first. Highest first, unknowns last; it sorts the returned page, andnext_cursorstill follows the library's order. Meta only; the TikTok library accepts onlyrelevance.analyzebooleanAd analysis on the first 50 Ads: 20 credits per Ad, whether computed or already stored at this Ad's current version. Meta only; the TikTok library refuses it.waitnumbervalue 0 to 120estimatebooleanMeta: When a source the call would read is unavailable and the answer is not served from cache, the estimate addsunavailable, the{ platform, capability }parts it cannot reach, or answers 503source_unavailablewhen it can reach none. A TikTok library estimate quotes the price without checking.
Responses
200 OK
The Run finished inside the wait budget: { run, result }. With estimate=true, { estimate_credits, cached } instead.
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.idstringrequiredkindstringrequiredWhat was run, e.g.video_lookup.statusstringrequiredone ofrunning,completed,partial,failedpartialkeeps the completed items and charges for them, up to what the Balance covers;failedcharges 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 tocharge_creditsunless 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, andanalysedofshortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.stagestringrequiredone ofkeywords,searching,filtering,analysing,writing_digestkeywordsintegervalue at least 0searchesintegervalue at least 0foundintegervalue at least 0judgedintegervalue at least 0keptintegervalue at least 0dropped_off_topicintegervalue at least 0dropped_unsureintegervalue at least 0shortlistedintegervalue at least 0analysedintegervalue at least 0updated_atstringrequired
resultobjectrequiredlibrarystringrequiredone ofmeta,tiktokitemsarray of objectrequiredlibrarystringrequiredone ofmeta,tiktokidstringrequiredurlstringrequirednullableadvertiserobjectrequiredidstringrequirednullablenamestringrequirednullable
is_activebooleanrequirednullablefirst_shownstringrequirednullablelast_shownstringrequirednullableplacementsarray of stringrequiredcreativeobjectrequiredtitlestringrequirednullablebodystringrequirednullablectastringrequirednullablelink_urlstringrequirednullableformatstringrequirednullableimage_urlsarray of stringrequiredvideo_urlsarray of stringrequiredthumbnail_urlsarray of stringrequired
reachobjectrequiredRanges as the library reports them, never coerced. Meta discloses spend and impressions for political and issue Ads, and reach (audience) for some EU Ads; otherwise null.impressionsstringrequirednullablespendstringrequirednullablecurrencystringrequirednullableaudiencestringrequirednullable
kindstringnullableone ofcommercial,political,issueMeta only.media_typestringnullableone ofvideo,image,carouselMeta only.countriesarray of stringnullableMeta only. Countries reached, when Meta discloses them.variant_countnumbernullableMeta only. How many Ads share this Ad's media; null for a single Ad.days_runningnumbernullableMeta only. Whole days from start to stop, or to now while running.archivedbooleanMeta only. True when every media URL is our permanent archived copy; false while any is still Meta's expiring URL (retried on the next sighting).winner_scoreobjectnullableMeta only. How strongly the Ad looks like a winner. 0 to 100, computed from the stored history of the Ad, never fetched. score = round(100 x (0.7 x rank(days_running) + 0.3 x rank(variants_added))), where rank is the share of the Advertiser's other Ads below this one (ties count half) and variants_added is the variant count at the latest Snapshot minus at the first. With one Snapshot the score is round(100 x rank(days_running)), confidence low, reason single_snapshot. With no other dated Ad of the Advertiser, rank falls back to min(days, 90)/90 and min(variants, 5)/5; under 5 dated Ads of the Advertiser the score is low confidence, reason few_advertiser_ads. No start date: score null, reason no_start_date.scorenumberrequirednullableconfidencestringrequiredone ofhigh,lowinputsobjectrequireddays_runningnumberrequirednullablevariants_addednumberrequiredsnapshotsnumberrequiredadvertiser_adsnumberrequiredDated Ads of this Advertiser stored so far, this one included.
reasonstringrequirednullableone ofsingle_snapshot,few_advertiser_ads,no_start_date
intelligenceany of 2 shapesnullableMeta only. Present when already computed for this Ad, or asked for withanalyze; null underanalyzewhen it could not be computed.Option 1objectVideo Ads: the full video analysis, read from the archived video with the ad copy as context.
versionintegerrequiredmodelstringrequiredcomputed_atstringrequiredsourcestringrequiredcontentobjectrequiredsummarystringrequirednichestringrequiredlanguagesarray of stringrequiredcontent_stylesarray of stringrequiredkeywordsarray of objectrequiredkeywordstringrequiredcategorystringrequiredsentimentnumberrequired
transcriptstringrequirednullable
hookobjectrequiredopening_linestringrequirednullabletypestringrequiredvisual_hookstringrequirednullablerationalestringrequirednullable
persuasionobjectrequiredcall_to_actionobjectrequiredtypestringrequiredtextstringrequirednullable
sponsoredbooleanrequiredsponsorship_signalsarray of stringrequiredbrands_and_productsarray of objectrequirednamestringrequiredkindstringrequiredprominencestringrequired
trend_referencesarray of objectrequirednamestringrequiredkindstringrequired
toneobjectrequiredsentiment_labelstringrequiredsentiment_scorenumberrequiredprimary_emotionstringrequiredemotion_intensitynumberrequirednullableemotion_rationalestringrequirednullablespeaking_stylestringrequiredspeaking_style_notesstringrequirednullable
visualobjectrequiredformatstringrequiredsettingstringrequiredface_visibilitystringrequiredon_screen_textarray of stringrequiredhas_on_screen_captionsbooleanrequiredcamera_notesstringrequirednullablelighting_notesstringrequirednullableelementsany
safetyobjectrequiredbrand_safety_tierstringrequiredreasonsarray of stringrequirednotesstringrequirednullable
pipelinestringrequiredalwaysvideo
Option 2objectImage and carousel Ads: the analysis an image can carry, read from the archived images with the ad copy as context.
pipelinestringrequiredalwaysimageversionintegerrequiredmodelstringrequiredcomputed_atstringrequiredimages_analyzedintegerrequiredsummarystringrequiredcopyobjectrequiredanglestringrequiredrationalestringrequirednullableheadlinestringrequirednullable
offerobjectrequiredtypestringrequiredtextstringrequirednullable
call_to_actionobjectrequiredtypestringrequiredtextstringrequirednullable
visualobjectrequiredformatstringrequiredon_image_textarray of stringrequired
topicsarray of stringrequiredtoneobjectrequiredsentiment_labelstringrequiredsentiment_scorenumberrequired
next_cursorstringrequirednullabletotalnumberrequirednullableWhat the library reports for the query, when it reports one and no filter was applied after fetching (anykindbutall,media_type,placements, a start date).cachedbooleanMetaadvertisersearches only: true when the Ads were served from the advertiser's last complete observation (under 6 hours old) at the cached per-Ad price.as_ofstringMetaadvertisersearches only: when these Ads were observed in the library.incompleteobjectMeta only, on apartialRun: the problem that stopped the read after some Ads were delivered.codestringrequireddetailstringrequired
intelligenceobjectPresent only withanalyze: true: Ads within the cap, how many were computed or reused (both charged) or failed (not charged). Per-Ad outcomes page atGET /v1/runs/{id}/items.requestedintegerrequiredcomputedintegerrequiredreusedintegerrequiredfailedintegerrequiredcapintegerrequired
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 Run finished inside the wait budget: `{ run, result }`. With `estimate=true`, `{ estimate_credits, cached }` instead.
{
"run": {
"id": "run_8f2c1ad04b",
"kind": "ads_search",
"status": "completed",
"created_at": "2026-09-08T09:14:02.418Z",
"completed_at": "2026-09-08T09:14:04.930Z",
"charge_credits": 2,
"list_price_credits": 2,
"cached": false
},
"result": {
"library": "meta",
"items": [
{
"library": "meta",
"id": "1122334455667788",
"url": "https://www.facebook.com/ads/library/?id=1122334455667788",
"advertiser": {
"id": "100064000000001",
"name": "Plunge"
},
"is_active": true,
"first_shown": "2026-08-01T00:00:00.000Z",
"last_shown": null,
"placements": [
"FACEBOOK",
"INSTAGRAM"
],
"creative": {
"title": "Cold water, on your schedule",
"body": "The tub our testers refused to give back.",
"cta": "Shop Now",
"link_url": "https://plunge.example/tub",
"format": "VIDEO",
"image_urls": [],
"video_urls": [
"https://video.xx.fbcdn.net/ads/plunge-tub-hd.mp4"
],
"thumbnail_urls": []
},
"reach": {
"impressions": null,
"spend": null,
"currency": null,
"audience": null
},
"kind": "commercial",
"media_type": "video",
"countries": null,
"variant_count": 4,
"days_running": 72,
"winner_score": {
"score": 88,
"confidence": "high",
"inputs": {
"days_running": 72,
"variants_added": 2,
"snapshots": 6,
"advertiser_ads": 14
},
"reason": null
}
},
{
"library": "meta",
"id": "2233445566778899",
"url": "https://www.facebook.com/ads/library/?id=2233445566778899",
"advertiser": {
"id": "100064000000001",
"name": "Plunge"
},
"is_active": false,
"first_shown": "2026-06-02T00:00:00.000Z",
"last_shown": "2026-07-14T00:00:00.000Z",
"placements": [
"INSTAGRAM"
],
"creative": {
"title": "Three minutes. Every morning.",
"body": "Our coldest tub yet, now in matte black.",
"cta": "Learn More",
"link_url": "https://plunge.example/black",
"format": "IMAGE",
"image_urls": [
"https://scontent.xx.fbcdn.net/ads/plunge-black.jpg"
],
"video_urls": [],
"thumbnail_urls": []
},
"reach": {
"impressions": null,
"spend": null,
"currency": null,
"audience": null
},
"kind": "commercial",
"media_type": "image",
"countries": null,
"variant_count": null,
"days_running": 42,
"winner_score": {
"score": 54,
"confidence": "low",
"inputs": {
"days_running": 42,
"variants_added": 0,
"snapshots": 1,
"advertiser_ads": 14
},
"reason": "single_snapshot"
}
}
],
"next_cursor": "eyJjIjoiQVpVWiIsIm8iOjB9",
"total": null
}
}200 · With `estimate=true`: the price, no Run, no charge.
{
"estimate_credits": 2,
"cached": false,
"per_ad_credits": 1,
"max_ads": 2,
"priced_per": "ad_delivered"
}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.idstringrequiredkindstringrequiredWhat was run, e.g.video_lookup.statusstringrequiredone ofrunning,completed,partial,failedpartialkeeps the completed items and charges for them, up to what the Balance covers;failedcharges 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 tocharge_creditsunless 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, andanalysedofshortlisted. A count is absent until its stage produced it. Absent once the Run settles, and on every other kind.stagestringrequiredone ofkeywords,searching,filtering,analysing,writing_digestkeywordsintegervalue at least 0searchesintegervalue at least 0foundintegervalue at least 0judgedintegervalue at least 0keptintegervalue at least 0dropped_off_topicintegervalue at least 0dropped_unsureintegervalue at least 0shortlistedintegervalue at least 0analysedintegervalue at least 0updated_atstringrequired
202 · Example
{
"run": {
"id": "run_8f2c1ad04b",
"kind": "ads_search",
"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.
typestringrequiredtitlestringrequiredstatusintegerrequiredcodestringrequiredone ofmissing_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.
typestringrequiredtitlestringrequiredstatusintegerrequiredcodestringrequiredone ofmissing_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.
typestringrequiredtitlestringrequiredstatusintegerrequiredcodestringrequiredone ofmissing_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": 2
}409 Conflict
idempotency_conflict — the same Idempotency-Key with a different payload.
object
RFC 9457 problem document, served as application/problem+json. Branch on code, never on the prose.
typestringrequiredtitlestringrequiredstatusintegerrequiredcodestringrequiredone ofmissing_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/idempotency_conflict",
"title": "Idempotency conflict",
"status": 409,
"code": "idempotency_conflict",
"detail": "This Idempotency-Key was used with a different payload.",
"run_id": "run_8f2c1ad04b"
}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.
typestringrequiredtitlestringrequiredstatusintegerrequiredcodestringrequiredone ofmissing_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.
typestringrequiredtitlestringrequiredstatusintegerrequiredcodestringrequiredone ofmissing_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": "ads_search",
"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.
typestringrequiredtitlestringrequiredstatusintegerrequiredcodestringrequiredone ofmissing_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": "ads_search",
"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/ads/search" \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"library":"meta","query":"cold plunge","country":"US","status":"active","kind":"commercial","media_type":"video","placements":["facebook"],"started_after":"2026-01-01","started_before":"2026-02-01","limit":20,"order_by":"relevance","analyze":true}'const response = await fetch(
"https://www.shortsintel.com/v1/ads/search",
{
method: "POST",
headers: {
"Authorization": "Bearer sk_live_YOUR_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
"library": "meta",
"query": "cold plunge",
"country": "US",
"status": "active",
"kind": "commercial",
"media_type": "video",
"placements": [
"facebook"
],
"started_after": "2026-01-01",
"started_before": "2026-02-01",
"limit": 20,
"order_by": "relevance",
"analyze": true
}),
},
);
if (!response.ok) {
throw new Error(`ShortsIntel ${response.status}`);
}
const data = await response.json();import requests
response = requests.post(
"https://www.shortsintel.com/v1/ads/search",
headers={
"Authorization": "Bearer sk_live_YOUR_KEY",
"Content-Type": "application/json",
},
json={
"library": "meta",
"query": "cold plunge",
"country": "US",
"status": "active",
"kind": "commercial",
"media_type": "video",
"placements": [
"facebook",
],
"started_after": "2026-01-01",
"started_before": "2026-02-01",
"limit": 20,
"order_by": "relevance",
"analyze": True,
},
)
response.raise_for_status()
data = response.json()Related guides
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.
- Ads: Searching Meta's Ad Library with its filters, what each Ad carries, the winner Score, Ad analysis, what is stored, and how an ad search is priced.