Magic AI API
Competitor / similar-ad discovery with an API key. Session UI uses /api/magic-ai; integrations must use /api/v1/magic-ai.
/api/v1/magic-aiFind similar Meta ads from text, image upload, or image URL.
X-API-Key on every request.Body parameters
textstringFree-text prompt. Provide text, image, or image_url.
image_urlstringPublic image URL.
imagefileMultipart image upload.
pageinteger0 on first request; increment when continuing.
scrollstringOpaque token from previous response; empty on first page.
limitintegerPage size on first request; max 50. Stored in scroll for continuations.
countriesstringComma-separated ISO codes or All.
exclude_countriesstringlanguagestringComma-separated language codes or All.
exclude_languagestringfromstringAd start date (from).
tostringAd start date (to).
fromlastseenstringtolastseenstringactivefilterstringSet to active to restrict to ads last seen within ~4 days.
minadspendstringmaxadspendstringminactiveadsstringmaxactiveadsstringads_per_brandintegerSet 1 for at most one ad per Facebook page.
mindaysstringmaxdaysstringadscorefilterstring
curl -sS \
-X POST \
-H "X-API-Key: $WH_API_KEY" \
-H "Content-Type: application/json" \
"{origin}/api/v1/magic-ai" \
-d '{"text":"string","image_url":"string","image":"string","page":0,"scroll":"string","limit":20,"countries":"All","exclude_countries":"string","language":"All","exclude_language":"string","from":"string","to":"string","fromlastseen":"string","tolastseen":"string","activefilter":"string","minadspend":"string","maxadspend":"string","minactiveads":"string","maxactiveads":"string","ads_per_brand":0,"mindays":"string","maxdays":"string","adscorefilter":"string"}'const res = await fetch(`${ORIGIN}/api/v1/magic-ai`, {
method: 'POST',
headers: {
'X-API-Key': process.env.WH_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"text": "string",
"image_url": "string",
"image": "string",
"page": 0,
"scroll": "string",
"limit": 20,
"countries": "All",
"exclude_countries": "string",
"language": "All",
"exclude_language": "string",
"from": "string",
"to": "string",
"fromlastseen": "string",
"tolastseen": "string",
"activefilter": "string",
"minadspend": "string",
"maxadspend": "string",
"minactiveads": "string",
"maxactiveads": "string",
"ads_per_brand": 0,
"mindays": "string",
"maxdays": "string",
"adscorefilter": "string"
}),
});
const data = await res.json();import os, requests
res = requests.post(
f"{ORIGIN}/api/v1/magic-ai",
headers={"X-API-Key": os.environ["WH_API_KEY"]},
json={
"text": "string",
"image_url": "string",
"image": "string",
"page": 0,
"scroll": "string",
"limit": 20,
"countries": "All",
"exclude_countries": "string",
"language": "All",
"exclude_language": "string",
"from": "string",
"to": "string",
"fromlastseen": "string",
"tolastseen": "string",
"activefilter": "string",
"minadspend": "string",
"maxadspend": "string",
"minactiveads": "string",
"maxactiveads": "string",
"ads_per_brand": 0,
"mindays": "string",
"maxdays": "string",
"adscorefilter": "string"
},
)
data = res.json(){
"data": [
{
"productid": "1284756102394857",
"page_id": "108897621643793",
"pageName": "Glow Beauty Co.",
"caption": "This serum changed my skin in 14 days…",
"copy": "This serum changed my skin in 14 days…",
"urlStore": "https://glowbeautyco.com/products/vitamin-c-serum",
"started": "2024-05-12",
"lastfoundago": "2 days ago",
"daysrunning": 128,
"adscore": "Winning",
"adscore_reasons": [
"Ad is running for longer than 7 days"
],
"countries": [
"US"
],
"saved": false,
"hidden": false
}
],
"scroll": "a1b2c3d4e5f6789012345678901234ab",
"limit": 20
}{
"success": false,
"error": "Invalid or expired scroll token"
}{
"success": false,
"error": "Unauthorized"
}{
"success": false,
"error": "WinningHunter Basic plan or higher required"
}{
"success": false,
"error": "No API credits remaining. Buy an add-on pack or wait until next monthly reset.",
"credits": {
"used": 20000,
"limit": 20000,
"remaining": 0,
"addon_remaining": 0,
"total_remaining": 0
},
"purchase": {
"url": "https://…/checkout-api-credits?credits=…"
}
}Body: application/x-www-form-urlencoded, multipart/form-data, or JSON (empty $_POST is filled from JSON).
Repeat the same search inputs and filters on each continuation with the returned scroll. Tokens expire after about 1 hour. Stop when scroll is empty/null or data is short.
Each data[] item is a full processed Meta ad card (Utils::process_ads) — same shape as brand ads and /api/v1/adlibrary. Use daysrunning (not days_running) and pageName (not page_name). There is no total field. Recency is commonly exposed as lastfoundago / enddate / started; lastSeen may also appear when present on the source card — do not require it. Missing input returns { "success": false, "error": "Missing search input. Provide text, image, or image_url." }. HTTP 500 may return { "data": [], "scroll": "" }.
Auth / metering: Authentication, Credits, Errors.