{"openapi":"3.1.0","info":{"title":"AdAlign API","version":"1.1.0","description":"Evaluate the congruence between paid media ads and their landing pages. Uses AI vision analysis to score four dimensions (visual match, message match, above-the-fold continuity and tone alignment) and returns ready-to-apply fixes. API access is included on the Scale plan and above."},"servers":[{"url":"https://app.adalign.io","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key with \"adal_\" prefix. Generate at Settings > API Keys (https://app.adalign.io/settings/api-keys)."}},"schemas":{"EvaluationRequest":{"type":"object","required":["adData","landingPageData"],"properties":{"adData":{"type":"object","description":"Provide imageUrl or adUrl. With neither, the request fails with 400 NO_AD_ASSET.","properties":{"imageUrl":{"type":"string","description":"URL of the ad image or video file."},"adUrl":{"type":"string","description":"URL of the ad itself (screenshotted automatically). Used when imageUrl is absent."},"platform":{"type":"string","enum":["meta","facebook","instagram","tiktok","linkedin","google","reddit"],"description":"Ad platform; picks the scoring weights. Recommended. If omitted, AdAlign detects the platform from the URLs or uses default weights."},"mediaType":{"type":"string","enum":["image","video","unknown"],"description":"Hint for adUrl. Video is otherwise detected from the URL."},"adTextFields":{"type":"object","description":"The ad copy as text, when known. Improves message match over reading copy from the image.","properties":{"headline":{"type":"string"},"bodyText":{"type":"string"},"description":{"type":"string"},"ctaType":{"type":"string","description":"e.g. SHOP_NOW, LEARN_MORE"},"pageName":{"type":"string","description":"Brand or page name"}}}}},"landingPageData":{"type":"object","properties":{"url":{"type":"string","description":"Public http(s) landing page URL to analyze"}},"required":["url"]},"viewport":{"type":"string","enum":["mobile","desktop"],"description":"Viewport for the landing page capture. Defaults to mobile for Meta/TikTok, desktop otherwise."},"audienceData":{"type":"object","description":"Optional targeting context.","properties":{"ageRange":{"type":"string"},"gender":{"type":"string"},"location":{"type":"string"},"interests":{"type":"string"}}}}},"EvaluationResponse":{"type":"object","properties":{"overallScore":{"type":"number","minimum":0,"maximum":10,"description":"Weighted overall score (1-10, 0.5 steps) using appliedProfile.weights"},"componentScores":{"type":"object","description":"Penalty-adjusted scores per dimension","properties":{"visualMatch":{"type":"number","minimum":0,"maximum":10,"description":"1-10 in 0.5 steps"},"messageMatch":{"type":"number","minimum":0,"maximum":10,"description":"Headline, offer, and CTA text alignment"},"aboveTheFoldContinuity":{"type":"number","minimum":0,"maximum":10,"description":"Above-fold promise confirmation and path clarity"},"toneAlignment":{"type":"number","minimum":0,"maximum":10,"description":"1-10 in 0.5 steps"},"contextualMatch":{"type":"number","description":"Legacy: average of messageMatch and aboveTheFoldContinuity"},"informationScent":{"type":"number","description":"DEPRECATED alias for aboveTheFoldContinuity.","deprecated":true}}},"rawScores":{"type":"object","description":"Scores before penalties and caps (same shape as componentScores)"},"detailedScores":{"type":"object","description":"Band-first scoring with reasoning per dimension","properties":{"visualMatch":{"type":"object","properties":{"score":{"type":"number"},"band":{"type":"string","enum":["EXCEPTIONAL","GOOD","MODERATE","POOR","VERY_POOR"]},"reasoning":{"type":"string"}}},"messageMatch":{"type":"object","properties":{"score":{"type":"number"},"band":{"type":"string","enum":["EXCEPTIONAL","GOOD","MODERATE","POOR","VERY_POOR"]},"reasoning":{"type":"string"}}},"aboveTheFoldContinuity":{"type":"object","properties":{"score":{"type":"number"},"band":{"type":"string","enum":["EXCEPTIONAL","GOOD","MODERATE","POOR","VERY_POOR"]},"reasoning":{"type":"string"}}},"toneAlignment":{"type":"object","properties":{"score":{"type":"number"},"band":{"type":"string","enum":["EXCEPTIONAL","GOOD","MODERATE","POOR","VERY_POOR"]},"reasoning":{"type":"string"}}},"informationScent":{"type":"object","properties":{"score":{"type":"number"},"band":{"type":"string","enum":["EXCEPTIONAL","GOOD","MODERATE","POOR","VERY_POOR"]},"reasoning":{"type":"string"}},"deprecated":true,"description":"DEPRECATED alias for aboveTheFoldContinuity."}}},"suggestions":{"type":"object","properties":{"visual":{"type":"array","items":{"type":"string"}},"contextual":{"type":"array","items":{"type":"string"}},"tone":{"type":"array","items":{"type":"string"}}}},"elementComparisons":{"type":"array","description":"Element-by-element comparisons between ad and landing page","items":{"type":"object","properties":{"element":{"type":"string"},"category":{"type":"string","enum":["visual","message","scent","tone"]},"adValue":{"type":"string"},"landingPageValue":{"type":"string"},"status":{"type":"string","enum":["match","mismatch","partial_match","missing","implicit","obscured"],"description":"implicit = present by convention (e.g. a product page CTA); obscured = hidden behind a cookie/consent modal, not scored"},"severity":{"type":"string","enum":["HIGH","MEDIUM","LOW"]},"recommendation":{"type":"string"}}}},"conversionRisks":{"type":"array","description":"Conversion risks derived from high-severity mismatches","items":{"type":"object","properties":{"type":{"type":"string","enum":["HEADLINE_DISCONNECT","CTA_FRICTION","OFFER_MISMATCH","BRAND_INCONSISTENCY"]},"message":{"type":"string"},"impact":{"type":"string","enum":["CRITICAL","HIGH","MEDIUM"]},"element":{"type":"string"}}}},"fixes":{"type":"array","description":"Ready-to-apply fixes. High-severity issues usually get several fixes with different directions.","items":{"$ref":"#/components/schemas/Fix"}},"appliedProfile":{"type":"object","description":"The platform/placement profile whose weights produced overallScore","properties":{"id":{"type":"string","description":"e.g. meta_feed, google_search, tiktok"},"platform":{"type":"string"},"surfaceLabel":{"type":"string"},"displayLabel":{"type":"string"},"weights":{"type":"object","properties":{"visualMatch":{"type":"number"},"messageMatch":{"type":"number"},"aboveTheFoldContinuity":{"type":"number"},"toneAlignment":{"type":"number"}}},"detectionReason":{"type":"string"},"detectionConfidence":{"type":"string","enum":["high","low"]}}},"detectionMode":{"type":"string","description":"How the profile was chosen, e.g. single or multi_placement"},"isPmax":{"type":"boolean"},"alternateScores":{"type":["array","null"],"description":"For multi-placement ads: overall score per other placement. overallScore is the weakest one.","items":{"type":"object","properties":{"profileId":{"type":"string"},"displayLabel":{"type":"string"},"surfaceLabel":{"type":["string","null"],"description":"Short placement name, e.g. \"Stories & Reels\""},"overallScore":{"type":"number"}}}},"evaluationId":{"type":"string","format":"uuid"},"adScreenshotUrl":{"type":"string"},"landingPageScreenshotUrl":{"type":["string","null"]},"alternateScreenshotUrl":{"type":["string","null"],"description":"Screenshot from the alternate viewport"},"alternateViewport":{"type":["string","null"],"enum":["mobile","desktop",null]},"analysisModel":{"type":"string","description":"Identifier of the analysis model version"},"mediaType":{"type":"string","enum":["image","video"]},"viewport":{"type":"string","enum":["mobile","desktop"]},"pageSpeedData":{"type":"object","description":"PageSpeed Insights data for the landing page, when available","properties":{"performanceScore":{"type":"number","description":"0-100"},"lcp":{"type":"number","description":"ms"},"fcp":{"type":"number","description":"ms"},"tbt":{"type":"number","description":"ms"},"cls":{"type":"number"},"si":{"type":"number","description":"Speed Index, ms"},"fetchedAt":{"type":"string","format":"date-time"}}},"videoFrames":{"type":["array","null"],"description":"Video ads only: extra frames analyzed"},"videoMetadata":{"type":"object","description":"Present only for video ad evaluations","properties":{"frameCount":{"type":"number"},"processingMethod":{"type":"string"},"hasTranscript":{"type":"boolean"},"transcriptLength":{"type":"number"},"videoDuration":{"type":["number","null"]}}}}},"UrlOnlyResponse":{"type":"object","description":"Returned with 200 when the landing page blocked every capture attempt. No scores; the evaluation is not counted.","properties":{"success":{"type":"boolean","const":true},"evaluationId":{"type":["string","null"]},"lpCaptureStatus":{"type":"string","const":"url_only"},"lpUnavailableReason":{"type":"string"},"scores":{"type":"null"},"detailedScores":{"type":"null"}}},"LinkBrokenResponse":{"type":"object","description":"Returned with 200 when the landing page is dead: it answers 404/410, its domain does not exist, its certificate is refused, or its title says \"not found\". Nothing is scored and the evaluation is not counted.","properties":{"success":{"type":"boolean","const":true},"evaluationId":{"type":["string","null"]},"lpCaptureStatus":{"type":"string","const":"link_broken"},"overallScore":{"type":"null"},"componentScores":{"type":"null"},"linkBroken":{"type":"object","properties":{"url":{"type":"string"},"finalUrl":{"type":["string","null"],"description":"Where redirects ended"},"httpStatus":{"type":["number","null"]},"reason":{"type":["string","null"],"description":"e.g. \"Returns 404 (page not found)\""}}},"landingPageScreenshotUrl":{"type":["string","null"],"description":"The error page as captured"}}},"Fix":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"element":{"type":"string","description":"The compared element this fix addresses"},"fixType":{"type":"string","enum":["headline","cta","body_copy","color","image","layout","offer","social_proof","urgency"]},"target":{"type":"string","enum":["ad","landing_page"]},"direction":{"type":"string","enum":["change_lp","change_ad","change_routing","change_both"],"description":"Which side the fix changes: the landing page, the ad, the routing (send the ad to a better page), or both."},"priority":{"type":"string","enum":["HIGH","MEDIUM","LOW"]},"currentValue":{"type":"string"},"suggestedValue":{"type":"string"},"cssSelector":{"type":"string"},"reasoning":{"type":"string"},"expectedImpact":{"type":"string"},"implementationSteps":{"type":"array","items":{"type":"string"}},"confidenceScore":{"type":"number","description":"0-1"},"tradeoff":{"type":"string"}}},"StoredFix":{"type":"object","description":"A fix as stored and returned by /api/fixes","properties":{"id":{"type":"string","format":"uuid"},"evaluationId":{"type":"string","format":"uuid"},"element":{"type":["string","null"]},"fixType":{"type":"string","enum":["headline","cta","body_copy","color","image","layout","offer","social_proof","urgency"]},"target":{"type":"string","enum":["ad","landing_page"]},"direction":{"type":["string","null"],"enum":["change_lp","change_ad","change_routing","change_both"],"description":"Which side the fix changes: the landing page, the ad, the routing (send the ad to a better page), or both."},"priority":{"type":"string","enum":["HIGH","MEDIUM","LOW"]},"status":{"type":"string","enum":["pending","applied","dismissed","expired"]},"currentValue":{"type":["string","null"]},"suggestedValue":{"type":"string"},"elementSelector":{"type":["string","null"]},"reasoning":{"type":["string","null"]},"expectedImpact":{"type":["string","null"]},"tradeoff":{"type":["string","null"]},"confidenceScore":{"type":["string","null"],"description":"Decimal string, 0.00-1.00"},"implementationSteps":{"type":["array","null"],"items":{"type":"string"}},"appliedAt":{"type":["string","null"],"format":"date-time"},"dismissedAt":{"type":["string","null"],"format":"date-time"},"dismissedReason":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"UsageInfo":{"type":"object","properties":{"used":{"type":"integer"},"limit":{"type":"integer"},"remaining":{"type":"integer"},"canEvaluate":{"type":"boolean"},"nextReset":{"type":"string","format":"date-time"},"tier":{"type":"string","description":"Internal plan id (studio = Scale, enterprise = Portfolio/Enterprise). Absent for anonymous callers."},"userEmail":{"type":"string"},"ipAddress":{"type":"string","description":"Anonymous callers only, partly masked"}}},"HistoryItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":["string","null"]},"landingPageUrl":{"type":"string"},"platform":{"type":["string","null"]},"overallScore":{"type":"number","description":"0 for evaluations scored without a landing page"},"visualMatchScore":{"type":"number"},"messageMatchScore":{"type":"number"},"aboveTheFoldContinuityScore":{"type":"number"},"toneAlignmentScore":{"type":"number"},"contextualMatchScore":{"type":"number"},"informationScentScore":{"type":"number","deprecated":true},"adScreenshotUrl":{"type":["string","null"]},"landingPageScreenshotUrl":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","properties":{"error":{"type":"string"},"errorCode":{"type":"string","description":"Present on 400, 429, 500 and 503 from /api/analyze-ad"}}}}},"paths":{"/api/analyze-ad":{"post":{"summary":"Evaluate ad-to-landing page alignment","description":"Run an AI vision analysis comparing an ad creative with its landing page. Returns four dimension scores, element comparisons and fixes. Uses one evaluation from the monthly pool; failed calls are refunded. Without an API key the call runs anonymously (1 evaluation per IP per month).","operationId":"analyzeAd","tags":["Analysis"],"security":[{"bearerAuth":[]},{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvaluationRequest"}}}},"responses":{"200":{"description":"Evaluation completed, the landing page could not be captured (lpCaptureStatus = url_only), or it is dead (lpCaptureStatus = link_broken)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/EvaluationResponse"},{"$ref":"#/components/schemas/UrlOnlyResponse"},{"$ref":"#/components/schemas/LinkBrokenResponse"}]}}}},"400":{"description":"UNSAFE_URL, NO_AD_ASSET or AD_SCREENSHOT_FAILED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid, expired or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API key lacks the analyze scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"USER_RATE_LIMIT_EXCEEDED or IP_RATE_LIMIT_EXCEEDED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"ANALYSIS_FAILED","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/check-usage":{"get":{"summary":"Check remaining evaluations","description":"Returns this month's usage for the key owner. Without a key, returns the anonymous per-IP allowance.","operationId":"checkUsage","tags":["Usage"],"security":[{"bearerAuth":[]},{}],"responses":{"200":{"description":"Usage information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageInfo"}}}},"401":{"description":"Invalid, expired or revoked API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API key lacks the usage scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The account behind the key no longer exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/user-history":{"get":{"summary":"List past evaluations","description":"Returns the key owner's evaluations, newest first, paginated.","operationId":"getUserHistory","tags":["History"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Evaluation history","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"evaluations":{"type":"array","items":{"$ref":"#/components/schemas/HistoryItem"}},"count":{"type":"integer"},"hasMore":{"type":"boolean"},"offset":{"type":"integer"},"limit":{"type":"integer"},"userId":{"type":"string"}}}}}},"401":{"description":"No valid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API key lacks the history scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/fixes":{"get":{"summary":"Get fixes","description":"action=list returns the fixes for one evaluation (HIGH priority first). action=get returns one fix. action=stats counts every fix on your evaluations.","operationId":"getFixes","tags":["Fixes"],"parameters":[{"name":"action","in":"query","required":true,"schema":{"type":"string","enum":["list","get","stats"]}},{"name":"evaluationId","in":"query","schema":{"type":"string","format":"uuid"},"description":"Required for action=list"},{"name":"fixId","in":"query","schema":{"type":"string","format":"uuid"},"description":"Required for action=get"}],"responses":{"200":{"description":"Fixes data","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"anyOf":[{"type":"object","description":"action=list","properties":{"fixes":{"type":"array","items":{"$ref":"#/components/schemas/StoredFix"}},"total":{"type":"integer"},"pending":{"type":"integer"},"applied":{"type":"integer"},"dismissed":{"type":"integer"},"paywalled":{"type":"boolean"}}},{"$ref":"#/components/schemas/StoredFix"},{"type":"object","description":"action=stats","properties":{"total":{"type":"integer"},"pending":{"type":"integer"},"applied":{"type":"integer"},"dismissed":{"type":"integer"},"high_priority":{"type":"integer"},"medium_priority":{"type":"integer"},"low_priority":{"type":"integer"},"fix_types":{"type":"integer"}}}]}}}}}},"400":{"description":"Missing evaluationId/fixId or invalid action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No valid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"API key lacks the fixes scope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Evaluation or fix not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}