{"openapi":"3.0.3","info":{"title":"GetHookdAI API Documentation","description":"All endpoints require a Public API team token passed as `Authorization: Bearer <token>`. Each endpoint additionally requires the token to carry the relevant scope (shown in each operation summary, e.g. `explore:read`, `boards:write`).","version":"1.3.0"},"servers":[{"url":"https://app.gethookd.ai"}],"security":[{"bearerAuth":[]}],"paths":{"/api/v1/authcheck":{"get":{"summary":"Validate Public API token and return workspace info.\n\nVerifies the provided team API token and returns the authenticated workspace and token scopes.","operationId":"validatePublicAPITokenAndReturnWorkspaceInfoVerifiesTheProvidedTeamAPITokenAndReturnsTheAuthenticatedWorkspaceAndTokenScopes","description":"","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"authenticated":true,"workspace":{"id":123,"name":"Acme Team"},"scopes":["explore:read"]}},"properties":{"errors":{"type":"boolean","example":false},"data":{"type":"object","properties":{"authenticated":{"type":"boolean","example":true},"workspace":{"type":"object","properties":{"id":{"type":"integer","example":123},"name":{"type":"string","example":"Acme Team"}}},"scopes":{"type":"array","example":["explore:read"],"items":{"type":"string"}}}}}}}}},"401":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Invalid or expired token."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Invalid or expired token."}}}}}}},"tags":["Public API v1 — Auth"]}},"/api/v1/page-types":{"get":{"summary":"List active landing-page types.\n\nReturns the catalogue of active landing-page types that may be passed (by slug) to the `page_type` filter on GET /api/v1/explore.","operationId":"listActiveLandingPageTypes","description":"","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":[{"id":7,"slug":"quiz_page","title":"Quiz Page"},{"id":6,"slug":"vsl_page","title":"VSL Page"}]},"properties":{"errors":{"type":"boolean","example":false},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":7},"slug":{"type":"string","example":"quiz_page"},"title":{"type":"string","example":"Quiz Page"}}}}}}}}},"401":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Invalid or expired token."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Invalid or expired token."}}}}}}},"tags":["Public API v1 — Explore"]}},"/api/v1/explore":{"get":{"summary":"List ads with filtering and pagination.\n\nRequires a Public API token with scope: explore:read.","operationId":"listAdsWithFilteringAndPaginationRequiresAPublicAPITokenWithScopeExploreread","description":"","parameters":[{"in":"query","name":"page","description":"The page number.","example":1,"required":false,"schema":{"type":"integer","description":"The page number.","example":1}},{"in":"query","name":"per_page","description":"Number of items per page (1-100). Defaults to 20.","example":24,"required":false,"schema":{"type":"integer","description":"Number of items per page (1-100). Defaults to 20.","example":24}},{"in":"query","name":"query","description":"Free-text search query.","example":"supplements","required":false,"schema":{"type":"string","description":"Free-text search query.","example":"supplements"}},{"in":"query","name":"sort_column","description":"Sort column. One of: created_at, start_date, days_active, used_count, popularity.","example":"created_at","required":false,"schema":{"type":"string","enum":["created_at","start_date","days_active","used_count","popularity"],"description":"Sort column. One of: created_at, start_date, days_active, used_count, popularity.","example":"created_at"}},{"in":"query","name":"sort_direction","description":"Sort direction. One of: asc, desc.","example":"desc","required":false,"schema":{"type":"string","description":"Sort direction. One of: asc, desc.","example":"desc"}},{"in":"query","name":"start-date","description":"date Start date (YYYY-MM-DD). Requires end-date.","example":"2025-01-01","required":false,"schema":{"type":"string","description":"date Start date (YYYY-MM-DD). Requires end-date.","example":"2025-01-01"}},{"in":"query","name":"end-date","description":"date End date (must be >= start-date).","example":"2025-01-31","required":false,"schema":{"type":"string","description":"date End date (must be >= start-date).","example":"2025-01-31"}},{"in":"query","name":"status","description":"Filter by library status. One of: active, inactive.","example":"active","required":false,"schema":{"type":"string","description":"Filter by library status. One of: active, inactive.","example":"active"}},{"in":"query","name":"ad-format","description":"Display formats (CSV). Allowed: image, video, carousels, multi_images, multi_videos, dcos, dpas, events, page_likes, multi_medias.","example":"image,video","required":false,"schema":{"type":"string","description":"Display formats (CSV). Allowed: image, video, carousels, multi_images, multi_videos, dcos, dpas, events, page_likes, multi_medias.","example":"image,video"}},{"in":"query","name":"run-time","description":"Minimum days active.","example":7,"required":false,"schema":{"type":"integer","description":"Minimum days active.","example":7}},{"in":"query","name":"language","description":"Languages (CSV). Capitalized 2-letter ISO 639-1 code (Except: ZHT - Chinese Traditional, CEB - Cebuano, HMN - Hmong).","example":"EN,ES","required":false,"schema":{"type":"string","description":"Languages (CSV). Capitalized 2-letter ISO 639-1 code (Except: ZHT - Chinese Traditional, CEB - Cebuano, HMN - Hmong).","example":"EN,ES"}},{"in":"query","name":"platform","description":"Platforms (CSV).","example":"facebook,instagram","required":false,"schema":{"type":"string","description":"Platforms (CSV).","example":"facebook,instagram"}},{"in":"query","name":"niche","description":"Niches (CSV). Valid IDs: 1=Accessories, 2=Alcohol, 3=App/Software, 4=Automotive, 5=Beauty, 6=Book/Publishing, 7=Business/Professional, 8=Charity/NFP, 9=Info, 10=Entertainment, 11=Fashion, 12=Finance, 13=Food/Drink, 14=Games, 15=Government, 16=Health/Wellness, 17=Home/Garden, 18=Insurance, 19=Jewelry/Watches, 20=Kids/Baby, 21=Media/News, 22=Medical, 23=Pets, 24=Real Estate, 25=Service Business, 26=Sports/Outdoors, 27=Tech, 28=Travel, 29=Other, 30=Supplements.","example":"5,11,16","required":false,"schema":{"type":"string","description":"Niches (CSV). Valid IDs: 1=Accessories, 2=Alcohol, 3=App/Software, 4=Automotive, 5=Beauty, 6=Book/Publishing, 7=Business/Professional, 8=Charity/NFP, 9=Info, 10=Entertainment, 11=Fashion, 12=Finance, 13=Food/Drink, 14=Games, 15=Government, 16=Health/Wellness, 17=Home/Garden, 18=Insurance, 19=Jewelry/Watches, 20=Kids/Baby, 21=Media/News, 22=Medical, 23=Pets, 24=Real Estate, 25=Service Business, 26=Sports/Outdoors, 27=Tech, 28=Travel, 29=Other, 30=Supplements.","example":"5,11,16"}},{"in":"query","name":"page_type","description":"Landing-page types (CSV slugs, e.g. quiz_page, advertorial, vsl_page). Each slug must be a recognised active type; discover the full active slug list at GET /api/v1/page-types.","example":"quiz_page,vsl_page","required":false,"schema":{"type":"string","description":"Landing-page types (CSV slugs, e.g. quiz_page, advertorial, vsl_page). Each slug must be a recognised active type; discover the full active slug list at GET /api/v1/page-types.","example":"quiz_page,vsl_page"}},{"in":"query","name":"performance_scores","description":"Performance score buckets (CSV). One or more of: testing, scaling, growing, optimized, winning.","example":"optimized,winning","required":false,"schema":{"type":"string","description":"Performance score buckets (CSV). One or more of: testing, scaling, growing, optimized, winning.","example":"optimized,winning"}},{"in":"query","name":"used_count","description":"Creative usage. Minimum number of times used.","example":3,"required":false,"schema":{"type":"integer","description":"Creative usage. Minimum number of times used.","example":3}},{"in":"query","name":"video_lengths","description":"Video length filter (CSV). One or more of: less_than_1_min, 1_to_3_min, 3_to_5_min, more_than_5_min.","example":"1_to_3_min","required":false,"schema":{"type":"string","description":"Video length filter (CSV). One or more of: less_than_1_min, 1_to_3_min, 3_to_5_min, more_than_5_min.","example":"1_to_3_min"}},{"in":"query","name":"eu_transparency","description":"EU transparency flag. 0 or 1.","example":1,"required":false,"schema":{"type":"integer","description":"EU transparency flag. 0 or 1.","example":1}},{"in":"query","name":"eu_total_reach","description":"Minimum EU total reach. Filters ads with eu_total_reach >= value.","example":200,"required":false,"schema":{"type":"integer","description":"Minimum EU total reach. Filters ads with eu_total_reach >= value.","example":200}},{"in":"query","name":"gender_audience","description":"Gender audience filter (CSV). One or more of: all, men, women.","example":"men,women","required":false,"schema":{"type":"string","description":"Gender audience filter (CSV). One or more of: all, men, women.","example":"men,women"}},{"in":"query","name":"age_audience","description":"Age audience filter (CSV). One or more of: 13-17, 18-24, 25-34, 35-44, 45-54, 55-64, 65.","example":"25-34,35-44","required":false,"schema":{"type":"string","description":"Age audience filter (CSV). One or more of: 13-17, 18-24, 25-34, 35-44, 45-54, 55-64, 65.","example":"25-34,35-44"}},{"in":"query","name":"location","description":"Capitalized 2-letter country codes (CSV). Use \"all\" to not filter.","example":"US,DE","required":false,"schema":{"type":"string","description":"Capitalized 2-letter country codes (CSV). Use \"all\" to not filter.","example":"US,DE"}},{"in":"query","name":"ad_spend_range","description":"Spend buckets (CSV, keys 1..6).","example":"3,4","required":false,"schema":{"type":"string","description":"Spend buckets (CSV, keys 1..6).","example":"3,4"}},{"in":"query","name":"excluded_brands","description":"Exclude brand IDs (CSV).","example":"10,11","required":false,"schema":{"type":"string","description":"Exclude brand IDs (CSV).","example":"10,11"}},{"in":"query","name":"creative_categories","description":"Creative category IDs (CSV). Valid IDs: 1=Before and After, 2=Testimonial - Reviews, 8=Promotion and Discount, 11=FAQ Explainers, 12=Holiday - Seasonal Theme, 14=Humor/Fun, 16=Reasons why, 17=Facts and Stats, 18=Features and Benefits, 19=Media and Press, 20=Us vs Them.","example":"1,17","required":false,"schema":{"type":"string","description":"Creative category IDs (CSV). Valid IDs: 1=Before and After, 2=Testimonial - Reviews, 8=Promotion and Discount, 11=FAQ Explainers, 12=Holiday - Seasonal Theme, 14=Humor/Fun, 16=Reasons why, 17=Facts and Stats, 18=Features and Benefits, 19=Media and Press, 20=Us vs Them.","example":"1,17"}},{"in":"query","name":"cta_types","description":"CTA types (CSV). Common values: SHOP_NOW, LEARN_MORE, SIGN_UP, DOWNLOAD, BOOK_NOW, CONTACT_US, GET_OFFER.","example":"SHOP_NOW,LEARN_MORE","required":false,"schema":{"type":"string","description":"CTA types (CSV). Common values: SHOP_NOW, LEARN_MORE, SIGN_UP, DOWNLOAD, BOOK_NOW, CONTACT_US, GET_OFFER.","example":"SHOP_NOW,LEARN_MORE"}},{"in":"query","name":"active_ads_count","description":"Minimum active ads per brand.","example":5,"required":false,"schema":{"type":"integer","description":"Minimum active ads per brand.","example":5}},{"in":"query","name":"ads_per_brand_limit","description":"Limit results per brand (1-50).","example":2,"required":false,"schema":{"type":"integer","description":"Limit results per brand (1-50).","example":2}},{"in":"query","name":"min_ad_copy_length","description":"Minimum ad copy (body) character length (1-10000).","example":100,"required":false,"schema":{"type":"integer","description":"Minimum ad copy (body) character length (1-10000).","example":100}},{"in":"query","name":"max_ad_copy_length","description":"Maximum ad copy (body) character length (1-10000). When both are present, must be >= min_ad_copy_length.","example":500,"required":false,"schema":{"type":"integer","description":"Maximum ad copy (body) character length (1-10000). When both are present, must be >= min_ad_copy_length.","example":500}},{"in":"query","name":"technologies","description":"Technologies the brand uses (CSV slugs, e.g. shopify,woocommerce,klaviyo).","example":"shopify,klaviyo","required":false,"schema":{"type":"string","description":"Technologies the brand uses (CSV slugs, e.g. shopify,woocommerce,klaviyo).","example":"shopify,klaviyo"}},{"in":"query","name":"brand_id","description":"Filter to a single brand by ID. Required when landing_page_url is supplied.","example":12345,"required":false,"schema":{"type":"integer","description":"Filter to a single brand by ID. Required when landing_page_url is supplied.","example":12345}},{"in":"query","name":"landing_page_url","description":"Filter by landing-page URL (max 2048 chars). Requires brand_id; pair with landing_page_match to control matching.","example":"https://example.com/offer","required":false,"schema":{"type":"string","description":"Filter by landing-page URL (max 2048 chars). Requires brand_id; pair with landing_page_match to control matching.","example":"https://example.com/offer"}},{"in":"query","name":"landing_page_match","description":"Landing-page URL matching mode. Only 'exact' is supported. Requires landing_page_url.","example":"exact","required":false,"schema":{"type":"string","enum":["exact"],"description":"Landing-page URL matching mode. Only 'exact' is supported. Requires landing_page_url.","example":"exact"}},{"in":"query","name":"ranking_method","description":"Ranking method. One of: impressions, run_time, duplication, custom. When 'custom', custom_weights must sum to 100.","example":"impressions","required":false,"schema":{"type":"string","enum":["impressions","run_time","duplication","custom"],"description":"Ranking method. One of: impressions, run_time, duplication, custom. When 'custom', custom_weights must sum to 100.","example":"impressions"}},{"in":"query","name":"percentile_floor","description":"Continuous top-percentile cutoff (0-99). 0 = all; 1..99 keeps ads at/above that percentile.","example":80,"required":false,"schema":{"type":"integer","description":"Continuous top-percentile cutoff (0-99). 0 = all; 1..99 keeps ads at/above that percentile.","example":80}},{"in":"query","name":"custom_weights","description":"Custom ranking weights (bracket notation, e.g. custom_weights[impressions]=60&custom_weights[run_time]=40). Each 0-100; required to sum to exactly 100 when ranking_method=custom.","required":false,"style":"deepObject","explode":true,"schema":{"type":"object","description":"Custom ranking weights. Each 0-100; must sum to 100 when ranking_method=custom.","properties":{"impressions":{"type":"integer","minimum":0,"maximum":100,"example":60},"run_time":{"type":"integer","minimum":0,"maximum":100,"example":40},"duplication":{"type":"integer","minimum":0,"maximum":100,"example":0}}}},{"in":"query","name":"collapse_variants","description":"Opt-in creative-variant collapsing. When true, duplicate variants collapse into one row stamped with variant_count. Accepts 1/0/true/false/on/off/yes/no.","example":"true","required":false,"schema":{"type":"string","enum":["1","0","true","false","on","off","yes","no"],"description":"Opt-in creative-variant collapsing. When true, duplicate variants collapse into one row stamped with variant_count. Accepts 1/0/true/false/on/off/yes/no.","example":"true"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":[{"id":123,"external_id":"9999999","platform":"facebook","display_format":"video","title":"Great offer","body":"Check out our latest deal...","landing_page":"https://example.com","link_description":"Shop now","cta_type":"SHOP_NOW","cta_text":"Shop Now","start_date":"2025-01-05","end_date":null,"days_active":21,"active_in_library":1,"used_count":4,"is_aaa_eligible":1,"age_audience_min":25,"age_audience_max":34,"gender_audience":"All","eu_total_reach":5000,"ad_spend_range_score":3,"ad_spend_range_score_title":"$2,001 - $5,000","performance_score":120,"performance_score_title":"Winning","share_url":"https://app.gethookd.ai/share/ad/123","brand":{"external_id":"2016485295279615","name":"Acme","logo_url":"https://example.com/logo.png","active_ads":109},"media":[{"type":"video","url":"https://example.com/video.mp4","resized_url":"https://example.com/video-resized.mp4","thumbnail_url":"https://example.com/thumb.jpg","video_length":30}],"ad_cards":[{"title":"Variant A","body":"Ad card body text","caption":"Caption text","cta_text":"Shop Now","cta_type":"SHOP_NOW","landing_page":"https://example.com/variant-a","media":[{"type":"image","url":"https://example.com/card.jpg","resized_url":"https://example.com/card-resized.jpg","thumbnail_url":"https://example.com/card-thumb.jpg","video_length":0}]}]}],"used_credits":0.2,"remaining_credits":1199.8,"sorting":{"column":"created_at","direction":"desc"},"filters":{"platforms":["facebook"]}},"properties":{"errors":{"type":"boolean","example":false},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicAd"}},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8},"sorting":{"type":"object","properties":{"column":{"type":"string","example":"created_at"},"direction":{"type":"string","example":"desc"}}},"filters":{"type":"object","properties":{"platforms":{"type":"array","items":{"type":"string"},"example":["facebook"]}}}}}}}},"401":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Unauthenticated."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Unauthenticated."}}}}}},"402":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Not enough credits"},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Not enough credits"}}}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Unrecognized parameter(s): foo"},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Unrecognized parameter(s): foo"}}}}}}},"tags":["Public API v1 — Explore"]}},"/api/v1/brandspy":{"get":{"summary":"List spied brands with pagination.\n\nRequires a Public API token with scope: brand-spy:read.","operationId":"listSpiedBrandsWithPagination","description":"","parameters":[{"in":"query","name":"page","description":"The page number.","example":1,"required":false,"schema":{"type":"integer","description":"The page number.","example":1}},{"in":"query","name":"per_page","description":"Number of items per page (1-100). Defaults to 20.","example":20,"required":false,"schema":{"type":"integer","description":"Number of items per page (1-100). Defaults to 20.","example":20}},{"in":"query","name":"sort_column","description":"Sort column. One of: created_at, active_ads, inactive_ads, last_spied_at, ads_change, growth_percent.","example":"created_at","required":false,"schema":{"type":"string","enum":["created_at","active_ads","inactive_ads","last_spied_at","ads_change","growth_percent"],"description":"Sort column. One of: created_at, active_ads, inactive_ads, last_spied_at, ads_change (absolute ads delta), growth_percent (percentage ads delta).","example":"created_at"}},{"in":"query","name":"sort_direction","description":"Sort direction. One of: asc, desc.","example":"desc","required":false,"schema":{"type":"string","description":"Sort direction. One of: asc, desc.","example":"desc"}},{"in":"query","name":"search","description":"Free-text substring match against the spied brand name.","example":"nike","required":false,"schema":{"type":"string","description":"Free-text substring match against the spied brand name.","example":"nike"}},{"in":"query","name":"parent_categories","description":"Filter by niche / parent-category IDs (CSV of integers).","example":"5,11","required":false,"schema":{"type":"string","description":"Filter by niche / parent-category IDs (CSV of integers).","example":"5,11"}},{"in":"query","name":"favourites_only","description":"When true, return only brands marked as favourite.","example":true,"required":false,"schema":{"type":"boolean","description":"When true, return only brands marked as favourite.","example":true}},{"in":"query","name":"folders","description":"Filter by folder / collection IDs owned by your workspace (CSV of integers).","example":"12,34","required":false,"schema":{"type":"string","description":"Filter by folder / collection IDs owned by your workspace (CSV of integers).","example":"12,34"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":[{"id":1,"brand_id":456,"brand_external_id":"2016485295279615","brand_name":"Acme","brand_logo_url":"https://example.com/logo.png","status":"1","active_ads":109,"inactive_ads":23,"videos":45,"images":64,"carousels":23,"created_at":"2025-01-15T10:30:00+00:00","last_spied_at":"2025-03-01T14:00:00+00:00"}],"meta":{"current_page":1,"per_page":20,"total":5,"last_page":1},"used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicSpiedBrand"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"}},"tags":["Public API v1 — BrandSpy"]},"post":{"summary":"Add a brand to BrandSpy.\n\nRequires a Public API token with scope: brand-spy:write.","operationId":"addBrandToBrandSpy","description":"","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["brand_id"],"properties":{"brand_id":{"type":"integer","description":"The ID of the brand to spy on. Must exist in the brands table.","example":456}}}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"id":1,"brand_id":456,"brand_external_id":"2016485295279615","brand_name":"Acme","brand_logo_url":"https://example.com/logo.png","status":"1","active_ads":109,"inactive_ads":0,"videos":0,"images":0,"carousels":0,"created_at":"2025-03-01T14:00:00+00:00","last_spied_at":null},"message":"Brand added to BrandSpy.","used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"$ref":"#/components/schemas/PublicSpiedBrand"},"message":{"type":"string","example":"Brand added to BrandSpy."},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Brand is already being spied on."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Brand is already being spied on."}}}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"The brand id field is required."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"The brand id field is required."}}}}}}},"tags":["Public API v1 — BrandSpy"]}},"/api/v1/brandspy/{brand_id}":{"get":{"summary":"Show brand details with paginated ads.\n\nRequires a Public API token with scope: brand-spy:read.","operationId":"showSpiedBrandWithAds","description":"","parameters":[{"in":"path","name":"brand_id","description":"The brand ID.","example":456,"required":true,"schema":{"type":"integer","description":"The brand ID.","example":456}},{"in":"query","name":"page","description":"The page number.","example":1,"required":false,"schema":{"type":"integer","description":"The page number.","example":1}},{"in":"query","name":"per_page","description":"Number of ads per page (1-100). Defaults to 20.","example":20,"required":false,"schema":{"type":"integer","description":"Number of ads per page (1-100). Defaults to 20.","example":20}},{"in":"query","name":"status","description":"Filter by ad status. One of: active, inactive.","example":"active","required":false,"schema":{"type":"string","description":"Filter by ad status. One of: active, inactive.","example":"active"}},{"in":"query","name":"platform","description":"Filter by platform. One of: facebook, instagram, tiktok, youtube, twitter, pinterest, snapchat, linkedin.","example":"facebook","required":false,"schema":{"type":"string","description":"Filter by platform. One of: facebook, instagram, tiktok, youtube, twitter, pinterest, snapchat, linkedin.","example":"facebook"}},{"in":"query","name":"ad-format","description":"Filter by ad format. One of: image, video, carousel, dco, dpa, event, page_like, multi_images.","example":"video","required":false,"schema":{"type":"string","description":"Filter by ad format. One of: image, video, carousel, dco, dpa, event, page_like, multi_images.","example":"video"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"id":1,"brand_id":456,"brand_external_id":"2016485295279615","brand_name":"Acme","brand_logo_url":"https://example.com/logo.png","status":"1","active_ads":109,"inactive_ads":23,"videos":45,"images":64,"carousels":23,"created_at":"2025-01-15T10:30:00+00:00","last_spied_at":"2025-03-01T14:00:00+00:00","ads":{"data":[],"current_page":1,"per_page":20,"total":109,"last_page":6}},"used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"allOf":[{"$ref":"#/components/schemas/PublicSpiedBrand"},{"type":"object","properties":{"ads":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicAd"}},"current_page":{"type":"integer","example":1},"per_page":{"type":"integer","example":20},"total":{"type":"integer","example":109},"last_page":{"type":"integer","example":6}}}}}]},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Spied brand not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Spied brand not found."}}}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Invalid status. Allowed: active, inactive."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Invalid status. Allowed: active, inactive."}}}}}}},"tags":["Public API v1 — BrandSpy"]},"delete":{"summary":"Remove a brand from BrandSpy.\n\nRequires a Public API token with scope: brand-spy:write.","operationId":"removeBrandFromBrandSpy","description":"","parameters":[{"in":"path","name":"brand_id","description":"The brand ID to remove.","example":456,"required":true,"schema":{"type":"integer","description":"The brand ID to remove.","example":456}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"message":"Brand removed from BrandSpy.","used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"message":{"type":"string","example":"Brand removed from BrandSpy."},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Brand not found in your spied list."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Brand not found in your spied list."}}}}}}},"tags":["Public API v1 — BrandSpy"]}},"/api/v1/swipefile":{"get":{"summary":"List saved ads in swipe file with pagination.\n\nRequires a Public API token with scope: swipe-file:read.","operationId":"listSavedAdsInSwipeFile","description":"","parameters":[{"in":"query","name":"page","description":"The page number.","example":1,"required":false,"schema":{"type":"integer","description":"The page number.","example":1}},{"in":"query","name":"per_page","description":"Number of items per page (1-100). Defaults to 20.","example":20,"required":false,"schema":{"type":"integer","description":"Number of items per page (1-100). Defaults to 20.","example":20}},{"in":"query","name":"sort_column","description":"Sort column. One of: created_at, start_date, days_active, used_count, popularity.","example":"created_at","required":false,"schema":{"type":"string","enum":["created_at","start_date","days_active","used_count","popularity"],"description":"Sort column. One of: created_at, start_date, days_active, used_count, popularity.","example":"created_at"}},{"in":"query","name":"sort_direction","description":"Sort direction. One of: asc, desc.","example":"desc","required":false,"schema":{"type":"string","description":"Sort direction. One of: asc, desc.","example":"desc"}},{"in":"query","name":"search","description":"Free-text substring match against the saved ad (max 500 chars).","example":"skincare","required":false,"schema":{"type":"string","description":"Free-text substring match against the saved ad (max 500 chars).","example":"skincare"}},{"in":"query","name":"active_in_library","description":"Filter by Meta ad-library activity. 1 = still active, 0 = inactive.","example":1,"required":false,"schema":{"type":"integer","enum":[0,1],"description":"Filter by Meta ad-library activity. 1 = still active, 0 = inactive.","example":1}},{"in":"query","name":"days_active","description":"Minimum number of days the ad has been running.","example":30,"required":false,"schema":{"type":"integer","description":"Minimum number of days the ad has been running.","example":30}},{"in":"query","name":"used_count","description":"Minimum number of times the creative has been used.","example":3,"required":false,"schema":{"type":"integer","description":"Minimum number of times the creative has been used.","example":3}},{"in":"query","name":"ads_per_brand_limit","description":"Limit results per brand (1-50).","example":2,"required":false,"schema":{"type":"integer","description":"Limit results per brand (1-50).","example":2}},{"in":"query","name":"min_ad_copy_length","description":"Minimum ad copy (body) character length (1-10000).","example":100,"required":false,"schema":{"type":"integer","description":"Minimum ad copy (body) character length (1-10000).","example":100}},{"in":"query","name":"max_ad_copy_length","description":"Maximum ad copy (body) character length (1-10000). When both are present, must be >= min_ad_copy_length.","example":500,"required":false,"schema":{"type":"integer","description":"Maximum ad copy (body) character length (1-10000). When both are present, must be >= min_ad_copy_length.","example":500}},{"in":"query","name":"from_date","description":"Start of the ad start-date range (inclusive). Required when to_date is supplied.","example":"2025-01-01","required":false,"schema":{"type":"string","format":"date","description":"Start of the ad start-date range (inclusive). Required when to_date is supplied.","example":"2025-01-01"}},{"in":"query","name":"to_date","description":"End of the ad start-date range (inclusive). Must be on/after from_date.","example":"2025-03-31","required":false,"schema":{"type":"string","format":"date","description":"End of the ad start-date range (inclusive). Must be on/after from_date.","example":"2025-03-31"}},{"in":"query","name":"parent_categories","description":"Filter by niche / parent-category IDs. Repeat the param (parent_categories[]=5&parent_categories[]=11). Max 50.","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"integer","minimum":1},"example":[5,11]}},{"in":"query","name":"excluded_brands","description":"Brand IDs to exclude. Repeat the param (excluded_brands[]=1&excluded_brands[]=2). Max 100.","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"integer","minimum":1},"example":[1,2]}},{"in":"query","name":"creative_categories","description":"Creative-category IDs. Repeat the param (creative_categories[]=3). Max 50.","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"integer","minimum":1},"example":[3]}},{"in":"query","name":"tags","description":"Tag IDs. Repeat the param (tags[]=7). Max 50.","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"integer","minimum":1},"example":[7]}},{"in":"query","name":"languages","description":"Language codes. Repeat the param (languages[]=en). Max 50.","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","maxLength":10},"example":["en","es"]}},{"in":"query","name":"platforms","description":"Platform slugs. Repeat the param (platforms[]=facebook). Max 20.","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","maxLength":50},"example":["facebook","instagram"]}},{"in":"query","name":"winning_scores","description":"Performance tiers. Repeat the param (winning_scores[]=winning). Each one of: testing, scaling, winning. Max 20.","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","enum":["testing","scaling","winning"]},"example":["winning"]}},{"in":"query","name":"video_lengths","description":"Video-length buckets. Repeat the param (video_lengths[]=short). Max 20.","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","maxLength":50},"example":["short"]}},{"in":"query","name":"display_formats","description":"Display formats. Repeat the param (display_formats[]=video). Max 20.","required":false,"style":"form","explode":true,"schema":{"type":"array","items":{"type":"string","maxLength":50},"example":["video","image"]}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":[],"used_credits":0.2,"remaining_credits":1199.8,"meta":{"current_page":1,"per_page":20,"total":50,"last_page":3}},"properties":{"errors":{"type":"boolean","example":false},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicAd"}},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"The sort column field is invalid."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"The sort column field is invalid."}}}}}}},"tags":["Public API v1 — Swipe File"]},"post":{"summary":"Save an ad to swipe file.\n\nRequires a Public API token with scope: swipe-file:write.","operationId":"saveAdToSwipeFile","description":"","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ad_id"],"properties":{"ad_id":{"type":"integer","description":"The ID of the ad to save. Must exist in the ads table.","example":123}}}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"ad_id":123},"message":"Ad saved to swipe file.","used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"type":"object","properties":{"ad_id":{"type":"integer","example":123}}},"message":{"type":"string","example":"Ad saved to swipe file."},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Ad is already in your swipe file."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Ad is already in your swipe file."}}}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"The ad id field is required."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"The ad id field is required."}}}}}}},"tags":["Public API v1 — Swipe File"]}},"/api/v1/swipefile/{ad_id}":{"delete":{"summary":"Remove an ad from swipe file.\n\nRequires a Public API token with scope: swipe-file:write.","operationId":"removeAdFromSwipeFile","description":"","parameters":[{"in":"path","name":"ad_id","description":"The ad ID to remove.","example":123,"required":true,"schema":{"type":"integer","description":"The ad ID to remove.","example":123}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"message":"Ad removed from swipe file.","used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"message":{"type":"string","example":"Ad removed from swipe file."},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Ad not found in your swipe file."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Ad not found in your swipe file."}}}}}}},"tags":["Public API v1 — Swipe File"]}},"/api/v1/boards":{"get":{"summary":"List boards with pagination.\n\nRequires a Public API token with scope: boards:read.","operationId":"listBoards","description":"","parameters":[{"in":"query","name":"page","description":"The page number.","example":1,"required":false,"schema":{"type":"integer","description":"The page number.","example":1}},{"in":"query","name":"per_page","description":"Number of items per page (1-100). Defaults to 20.","example":20,"required":false,"schema":{"type":"integer","description":"Number of items per page (1-100). Defaults to 20.","example":20}},{"in":"query","name":"sort_column","description":"Sort column. One of: created_at, updated_at, name.","example":"created_at","required":false,"schema":{"type":"string","description":"Sort column. One of: created_at, updated_at, name.","example":"created_at"}},{"in":"query","name":"sort_direction","description":"Sort direction. One of: asc, desc.","example":"desc","required":false,"schema":{"type":"string","description":"Sort direction. One of: asc, desc.","example":"desc"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":[{"id":1,"name":"Top Performers","slug":"top-performers-1","ad_count":25,"is_public":true,"public_url":"https://app.gethookd.ai/share/board/top-performers-1","created_at":"2025-01-15T10:30:00+00:00","updated_at":"2025-03-01T14:00:00+00:00"}],"meta":{"current_page":1,"per_page":20,"total":3,"last_page":1},"used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicBoard"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"}},"tags":["Public API v1 — Boards"]},"post":{"summary":"Create a new board.\n\nRequires a Public API token with scope: boards:write.","operationId":"createBoard","description":"","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"The board name. Max 255 characters.","example":"Top Performers","maxLength":255},"is_public":{"type":"boolean","description":"Whether the board is publicly shareable. Defaults to false.","example":false}}}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"id":1,"name":"Top Performers","slug":"top-performers-1","ad_count":0,"is_public":false,"public_url":null,"created_at":"2025-03-01T14:00:00+00:00","updated_at":"2025-03-01T14:00:00+00:00"},"message":"Board created.","used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"$ref":"#/components/schemas/PublicBoard"},"message":{"type":"string","example":"Board created."},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"The name field is required."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"The name field is required."}}}}}}},"tags":["Public API v1 — Boards"]}},"/api/v1/boards/{board_id}":{"get":{"summary":"Get board details with paginated ads.\n\nRequires a Public API token with scope: boards:read.","operationId":"getBoardWithAds","description":"","parameters":[{"in":"path","name":"board_id","description":"The board ID.","example":1,"required":true,"schema":{"type":"integer","description":"The board ID.","example":1}},{"in":"query","name":"page","description":"The page number for ads.","example":1,"required":false,"schema":{"type":"integer","description":"The page number for ads.","example":1}},{"in":"query","name":"per_page","description":"Number of ads per page (1-100). Defaults to 20.","example":20,"required":false,"schema":{"type":"integer","description":"Number of ads per page (1-100). Defaults to 20.","example":20}},{"in":"query","name":"sort_column","description":"Sort the board's ads. One of: created_at, start_date, days_active, used_count. Defaults to created_at.","example":"created_at","required":false,"schema":{"type":"string","enum":["created_at","start_date","days_active","used_count"],"description":"Sort the board's ads. One of: created_at, start_date, days_active, used_count. Defaults to created_at.","example":"created_at"}},{"in":"query","name":"sort_direction","description":"Sort direction for the board's ads. One of: asc, desc. Defaults to desc.","example":"desc","required":false,"schema":{"type":"string","enum":["asc","desc"],"description":"Sort direction for the board's ads. One of: asc, desc. Defaults to desc.","example":"desc"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"id":1,"name":"Top Performers","slug":"top-performers-1","ad_count":25,"is_public":true,"public_url":"https://app.gethookd.ai/share/board/top-performers-1","created_at":"2025-01-15T10:30:00+00:00","updated_at":"2025-03-01T14:00:00+00:00","ads":{"data":[],"current_page":1,"per_page":20,"total":25,"last_page":2}},"used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"allOf":[{"$ref":"#/components/schemas/PublicBoard"},{"type":"object","properties":{"ads":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicAd"}},"current_page":{"type":"integer","example":1},"per_page":{"type":"integer","example":20},"total":{"type":"integer","example":25},"last_page":{"type":"integer","example":2}}}}}]},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Board not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Board not found."}}}}}}},"tags":["Public API v1 — Boards"]},"put":{"summary":"Update a board.\n\nRequires a Public API token with scope: boards:write.","operationId":"updateBoard","description":"","parameters":[{"in":"path","name":"board_id","description":"The board ID.","example":1,"required":true,"schema":{"type":"integer","description":"The board ID.","example":1}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"The board name. Max 255 characters.","example":"Updated Board Name","maxLength":255},"is_public":{"type":"boolean","description":"Whether the board is publicly shareable.","example":true}}}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"id":1,"name":"Updated Board Name","slug":"updated-board-name-1","ad_count":25,"is_public":true,"public_url":"https://app.gethookd.ai/share/board/updated-board-name-1","created_at":"2025-01-15T10:30:00+00:00","updated_at":"2025-03-05T14:00:00+00:00"},"used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"$ref":"#/components/schemas/PublicBoard"},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Board not found or you do not have permission to update it."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Board not found or you do not have permission to update it."}}}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"The name must be a string."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"The name must be a string."}}}}}}},"tags":["Public API v1 — Boards"]},"delete":{"summary":"Delete a board.\n\nRequires a Public API token with scope: boards:write.","operationId":"deleteBoard","description":"","parameters":[{"in":"path","name":"board_id","description":"The board ID to delete.","example":1,"required":true,"schema":{"type":"integer","description":"The board ID to delete.","example":1}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"message":"Board deleted.","used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"message":{"type":"string","example":"Board deleted."},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Board not found or you do not have permission to delete it."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Board not found or you do not have permission to delete it."}}}}}}},"tags":["Public API v1 — Boards"]}},"/api/v1/boards/{board_id}/ads":{"post":{"summary":"Add an ad to a board.\n\nRequires a Public API token with scope: boards:write.","operationId":"addAdToBoard","description":"","parameters":[{"in":"path","name":"board_id","description":"The board ID.","example":1,"required":true,"schema":{"type":"integer","description":"The board ID.","example":1}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ad_id"],"properties":{"ad_id":{"type":"integer","description":"The ID of the ad to add. Must exist in the ads table.","example":123}}}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"board_id":1,"ad_id":123},"message":"Ad added to board.","used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"type":"object","properties":{"board_id":{"type":"integer","example":1},"ad_id":{"type":"integer","example":123}}},"message":{"type":"string","example":"Ad added to board."},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Board not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Board not found."}}}}}},"409":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Ad is already on this board."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Ad is already on this board."}}}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"The ad id field is required."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"The ad id field is required."}}}}}}},"tags":["Public API v1 — Boards"]}},"/api/v1/boards/{board_id}/ads/{ad_id}":{"delete":{"summary":"Remove an ad from a board.\n\nRequires a Public API token with scope: boards:write.","operationId":"removeAdFromBoard","description":"","parameters":[{"in":"path","name":"board_id","description":"The board ID.","example":1,"required":true,"schema":{"type":"integer","description":"The board ID.","example":1}},{"in":"path","name":"ad_id","description":"The ad ID to remove.","example":123,"required":true,"schema":{"type":"integer","description":"The ad ID to remove.","example":123}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"message":"Ad removed from board.","used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"message":{"type":"string","example":"Ad removed from board."},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Ad not found on this board."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Ad not found on this board."}}}}}}},"tags":["Public API v1 — Boards"]}},"/api/v1/clone-ads":{"get":{"summary":"List clone ads with pagination.\n\nRequires a Public API token with scope: clone-ads:read.","operationId":"listCloneAds","description":"","parameters":[{"in":"query","name":"page","description":"The page number.","example":1,"required":false,"schema":{"type":"integer","description":"The page number.","example":1}},{"in":"query","name":"per_page","description":"Number of items per page (1-100). Defaults to 20.","example":20,"required":false,"schema":{"type":"integer","description":"Number of items per page (1-100). Defaults to 20.","example":20}},{"in":"query","name":"sort_direction","description":"Sort direction. One of: asc, desc. Sorts by created_at.","example":"desc","required":false,"schema":{"type":"string","description":"Sort direction. One of: asc, desc. Sorts by created_at.","example":"desc"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":[{"id":1,"title":"Clone of Ad #123","created_at":"2025-03-01T14:00:00+00:00","updated_at":"2025-03-01T14:05:00+00:00","prompts":[{"id":1,"prompt":"Clone ad #123","aspect_ratio":"Square","in_progress":false,"created_at":"2025-03-01T14:00:00+00:00","media":[{"id":1,"url":"https://example.com/generated-image.png","aspect_ratio":"Square","is_image_reference":false,"order":1}]}]}],"meta":{"current_page":1,"per_page":20,"total":10,"last_page":1},"used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicCloneAd"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"}},"tags":["Public API v1 — Clone Ads"]},"post":{"summary":"Create a clone ad from an existing ad.\n\nRequires a Public API token with scope: clone-ads:write. Generates AI image variations based on the source ad.","operationId":"createCloneAd","description":"","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ad_id"],"properties":{"ad_id":{"type":"integer","description":"The ID of the source ad to clone. Must exist in the ads table.","example":123},"product_id":{"type":"integer","description":"Optional product ID to drive the rich clone-ad pipeline. When provided it must belong to your workspace; otherwise a product is auto-resolved from the source ad.","example":456,"nullable":true},"prompt":{"type":"string","description":"Custom prompt for image generation. Max 4000 characters.","example":"Create a vibrant version with summer colors","maxLength":4000,"nullable":true},"aspect_ratio":{"type":"string","description":"Aspect ratio for generated images. One of: 'Square (1:1)', 'Portrait (9:16)', 'Landscape (16:9)', 'Portrait (2:3)', 'Landscape (3:2)', 'Portrait (3:4)', 'Landscape (4:3)'. Legacy bare names (Square, Portrait, Landscape) are also accepted and normalized. Defaults to 'Square (1:1)'.","example":"Square (1:1)","enum":["Square (1:1)","Portrait (9:16)","Landscape (16:9)","Portrait (2:3)","Landscape (3:2)","Portrait (3:4)","Landscape (4:3)"],"nullable":true},"variations_count":{"type":"integer","description":"Number of image variations to generate (1-10). Defaults to 3.","example":3,"minimum":1,"maximum":10,"nullable":true}}}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"id":1,"title":"Clone of Ad #123","created_at":"2025-03-01T14:00:00+00:00","updated_at":"2025-03-01T14:00:00+00:00","prompts":[{"id":1,"prompt":"Create a vibrant version with summer colors","aspect_ratio":"Square","in_progress":true,"created_at":"2025-03-01T14:00:00+00:00","media":[]}]},"used_credits":0.6,"remaining_credits":1199.4,"message":"Clone ad generated successfully."},"properties":{"errors":{"type":"boolean","example":false},"data":{"$ref":"#/components/schemas/PublicCloneAd"},"used_credits":{"type":"number","nullable":true,"example":0.6},"remaining_credits":{"type":"number","example":1199.4},"message":{"type":"string","example":"Clone ad generated successfully."}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"The ad id field is required."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"The ad id field is required."}}}}}}},"tags":["Public API v1 — Clone Ads"]}},"/api/v1/clone-ads/{clone_id}":{"get":{"summary":"Get a clone ad by ID.\n\nRequires a Public API token with scope: clone-ads:read.","operationId":"getCloneAd","description":"","parameters":[{"in":"path","name":"clone_id","description":"The clone ad ID.","example":1,"required":true,"schema":{"type":"integer","description":"The clone ad ID.","example":1}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":false,"data":{"id":1,"title":"Clone of Ad #123","created_at":"2025-03-01T14:00:00+00:00","updated_at":"2025-03-01T14:05:00+00:00","prompts":[{"id":1,"prompt":"Clone ad #123","aspect_ratio":"Square","in_progress":false,"created_at":"2025-03-01T14:00:00+00:00","media":[{"id":1,"url":"https://example.com/generated-image.png","aspect_ratio":"Square","is_image_reference":false,"order":1}]}]},"used_credits":0.2,"remaining_credits":1199.8},"properties":{"errors":{"type":"boolean","example":false},"data":{"$ref":"#/components/schemas/PublicCloneAd"},"used_credits":{"type":"number","nullable":true,"example":0.2},"remaining_credits":{"type":"number","example":1199.8}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Clone ad not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Clone ad not found."}}}}}}},"tags":["Public API v1 — Clone Ads"]}},"/api/v1/ads/{ad_id}":{"get":{"summary":"Get a single ad by ID.\n\nRequires a Public API token with scope: explore:read. Returns the same ad shape as the list endpoint. Single-ad lookup does not deduct credits.","operationId":"getAdById","description":"","parameters":[{"in":"path","name":"ad_id","description":"The internal ad ID.","example":12345,"required":true,"schema":{"type":"integer","description":"The internal ad ID.","example":12345}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"boolean","example":false},"data":{"$ref":"#/components/schemas/PublicAd"}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Ad not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Ad not found."}}}}}}},"tags":["Public API v1 — Explore"]}},"/api/v1/brands":{"get":{"summary":"Search the global brands catalog.\n\nRequires a Public API token with scope: brand-spy:read. No credit deduction — brand metadata is not billable.","operationId":"listBrands","description":"","parameters":[{"in":"query","name":"search","description":"Free-text substring match against the brand name.","example":"nike","required":false,"schema":{"type":"string","example":"nike"}},{"in":"query","name":"page","description":"The page number.","example":1,"required":false,"schema":{"type":"integer","example":1}},{"in":"query","name":"per_page","description":"Number of items per page (1-100). Defaults to 20.","example":50,"required":false,"schema":{"type":"integer","example":50}},{"in":"query","name":"sort_column","description":"Sort column. One of: name, active_ads, created_at. Defaults to name. Unrecognized values fall back to name (asc).","example":"active_ads","required":false,"schema":{"type":"string","example":"active_ads"}},{"in":"query","name":"sort_direction","description":"Sort direction. One of: asc, desc.","example":"desc","required":false,"schema":{"type":"string","example":"desc"}},{"in":"query","name":"parent_categories","description":"Niche / parent-category IDs (CSV). Non-integer values are silently dropped.","example":"5,16","required":false,"schema":{"type":"string","example":"5,16"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"boolean","example":false},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicBrand"}},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"}},"tags":["Public API v1 — Brands"]}},"/api/v1/brands/{brand_id}":{"get":{"summary":"Look up a single brand by its internal ID.\n\nRequires a Public API token with scope: brand-spy:read. No credit deduction.","operationId":"getBrandById","description":"","parameters":[{"in":"path","name":"brand_id","description":"The internal brand ID.","example":12345,"required":true,"schema":{"type":"integer","description":"The internal brand ID.","example":12345}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"boolean","example":false},"data":{"$ref":"#/components/schemas/PublicBrand"}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Brand not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Brand not found."}}}}}}},"tags":["Public API v1 — Brands"]}},"/api/v1/brandspy/{brand_id}/top-ads":{"get":{"summary":"List a brand's currently-running top-performing ads.\n\nRequires a Public API token with scope: brand-spy:read. Ranked by performance score (with global impression rank as tiebreaker). The brand must already be spied on by the authenticated workspace. No credit deduction.","operationId":"listBrandSpyTopAds","description":"","parameters":[{"in":"path","name":"brand_id","description":"The internal brand ID, or the spied-brand record ID.","example":12345,"required":true,"schema":{"type":"integer","description":"The internal brand ID, or the spied-brand record ID.","example":12345}},{"in":"query","name":"limit","description":"Number of ads to return (1-50). Defaults to 10.","example":25,"required":false,"schema":{"type":"integer","example":25}},{"in":"query","name":"platform","description":"Filter by platform. One of: facebook, instagram, tiktok, youtube, twitter, pinterest, snapchat, linkedin.","example":"facebook","required":false,"schema":{"type":"string","example":"facebook"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"boolean","example":false},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicAd"}},"meta":{"type":"object","properties":{"result_count":{"type":"integer","example":25}}}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Spied brand not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Spied brand not found."}}}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Invalid platform. Allowed: facebook, instagram, tiktok, youtube, twitter, pinterest, snapchat, linkedin."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Invalid platform. Allowed: facebook, instagram, tiktok, youtube, twitter, pinterest, snapchat, linkedin."}}}}}}},"tags":["Public API v1 — BrandSpy"]}},"/api/v1/searches":{"get":{"summary":"List saved searches with pagination.\n\nRequires a Public API token with scope: searches:read.","operationId":"listSavedSearches","description":"","parameters":[{"in":"query","name":"page","description":"The page number.","example":1,"required":false,"schema":{"type":"integer","example":1}},{"in":"query","name":"per_page","description":"Number of items per page (1-100). Defaults to 10.","example":10,"required":false,"schema":{"type":"integer","example":10}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"boolean","example":false},"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicSavedSearch"}},"used_credits":{"type":"number","nullable":true,"example":0.05},"remaining_credits":{"type":"number","example":1199.95},"meta":{"$ref":"#/components/schemas/PaginationMeta"}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"}},"tags":["Public API v1 — Saved Searches"]},"post":{"summary":"Create a saved search.\n\nRequires a Public API token with scope: searches:write.","operationId":"createSavedSearch","description":"","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSavedSearchInput"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"boolean","example":false},"message":{"type":"string","example":"Saved search created successfully."},"data":{"$ref":"#/components/schemas/PublicSavedSearch"},"used_credits":{"type":"number","nullable":true,"example":0.05},"remaining_credits":{"type":"number","example":1199.95}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"The name field is required."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"The name field is required."}}}}}},"500":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Unable to store saved search."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Unable to store saved search."}}}}}}},"tags":["Public API v1 — Saved Searches"]}},"/api/v1/searches/{search_id}":{"get":{"summary":"Get a saved search by ID.\n\nRequires a Public API token with scope: searches:read.","operationId":"getSavedSearch","description":"","parameters":[{"in":"path","name":"search_id","description":"The saved search ID.","example":42,"required":true,"schema":{"type":"integer","description":"The saved search ID.","example":42}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"boolean","example":false},"data":{"$ref":"#/components/schemas/PublicSavedSearch"},"used_credits":{"type":"number","nullable":true,"example":0.01},"remaining_credits":{"type":"number","example":1199.99}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Saved search not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Saved search not found."}}}}}}},"tags":["Public API v1 — Saved Searches"]},"put":{"summary":"Update a saved search.\n\nRequires a Public API token with scope: searches:write.","operationId":"updateSavedSearch","description":"","parameters":[{"in":"path","name":"search_id","description":"The saved search ID.","example":42,"required":true,"schema":{"type":"integer","description":"The saved search ID.","example":42}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSavedSearchInput"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"boolean","example":false},"message":{"type":"string","example":"Saved search updated successfully."},"data":{"$ref":"#/components/schemas/PublicSavedSearch"},"used_credits":{"type":"number","nullable":true,"example":0.02},"remaining_credits":{"type":"number","example":1199.98}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Saved search not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Saved search not found."}}}}}},"422":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"The name field is required."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"The name field is required."}}}}}},"500":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Unable to update saved search."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Unable to update saved search."}}}}}}},"tags":["Public API v1 — Saved Searches"]},"delete":{"summary":"Delete a saved search.\n\nRequires a Public API token with scope: searches:write.","operationId":"deleteSavedSearch","description":"","parameters":[{"in":"path","name":"search_id","description":"The saved search ID to delete.","example":42,"required":true,"schema":{"type":"integer","description":"The saved search ID to delete.","example":42}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object","properties":{"errors":{"type":"boolean","example":false},"message":{"type":"string","example":"Saved search deleted successfully."},"used_credits":{"type":"number","nullable":true,"example":0.01},"remaining_credits":{"type":"number","example":1199.99}}}}}},"401":{"$ref":"#/components/responses/Unauthenticated"},"402":{"$ref":"#/components/responses/InsufficientCredits"},"404":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Saved search not found."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Saved search not found."}}}}}},"500":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Unable to delete saved search."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Unable to delete saved search."}}}}}}},"tags":["Public API v1 — Saved Searches"]}}},"tags":[{"name":"Public API v1 — Auth"},{"name":"Public API v1 — Explore"},{"name":"Public API v1 — Brands"},{"name":"Public API v1 — BrandSpy"},{"name":"Public API v1 — Swipe File"},{"name":"Public API v1 — Boards"},{"name":"Public API v1 — Saved Searches"},{"name":"Public API v1 — Clone Ads"}],"components":{"schemas":{"PaginationMeta":{"type":"object","properties":{"current_page":{"type":"integer","example":1},"per_page":{"type":"integer","example":20},"total":{"type":"integer","example":100},"last_page":{"type":"integer","example":5}}},"PublicAd":{"type":"object","properties":{"id":{"type":"integer","example":123},"external_id":{"type":"string","example":"9999999"},"platform":{"type":"string","example":"facebook"},"display_format":{"type":"string","example":"video"},"title":{"type":"string","nullable":true,"example":"Great offer"},"body":{"type":"string","nullable":true,"example":"Check out our latest deal..."},"landing_page":{"type":"string","nullable":true,"example":"https://example.com"},"page_type":{"type":"string","nullable":true,"description":"Landing-page type slug (see GET /api/v1/page-types). Null when unclassified.","example":"quiz_page"},"link_description":{"type":"string","nullable":true,"example":"Shop now"},"cta_type":{"type":"string","nullable":true,"example":"SHOP_NOW"},"cta_text":{"type":"string","nullable":true,"example":"Shop Now"},"start_date":{"type":"string","nullable":true,"example":"2025-01-05"},"end_date":{"type":"string","nullable":true,"example":null},"days_active":{"type":"integer","nullable":true,"example":21},"active_in_library":{"type":"integer","nullable":true,"example":1},"used_count":{"type":"integer","nullable":true,"example":4},"is_aaa_eligible":{"type":"integer","nullable":true,"example":1},"age_audience_min":{"type":"integer","nullable":true,"example":25},"age_audience_max":{"type":"integer","nullable":true,"example":34},"gender_audience":{"type":"string","nullable":true,"example":"All"},"eu_total_reach":{"type":"integer","nullable":true,"example":5000},"ad_spend_range_score":{"type":"integer","nullable":true,"example":3},"ad_spend_range_score_title":{"type":"string","nullable":true,"example":"$2,001 - $5,000"},"performance_score":{"type":"integer","nullable":true,"example":120},"performance_score_title":{"type":"string","nullable":true,"example":"Winning"},"share_url":{"type":"string","nullable":true,"example":"https://app.gethookd.ai/share/ad/123"},"brand":{"$ref":"#/components/schemas/PublicBrand"},"media":{"type":"array","items":{"$ref":"#/components/schemas/PublicAdMedia"}},"ad_cards":{"type":"array","items":{"$ref":"#/components/schemas/PublicAdCard"}}}},"PublicBrand":{"type":"object","properties":{"external_id":{"type":"string","example":"2016485295279615"},"name":{"type":"string","example":"Acme"},"logo_url":{"type":"string","nullable":true,"example":"https://example.com/logo.png"},"active_ads":{"type":"integer","nullable":true,"example":109}}},"PublicAdMedia":{"type":"object","properties":{"type":{"type":"string","example":"video"},"url":{"type":"string","example":"https://example.com/video.mp4"},"resized_url":{"type":"string","nullable":true,"example":"https://example.com/video-resized.mp4"},"thumbnail_url":{"type":"string","nullable":true,"example":"https://example.com/thumb.jpg"},"video_length":{"type":"integer","nullable":true,"example":30}}},"PublicAdCard":{"type":"object","properties":{"title":{"type":"string","nullable":true,"example":"Variant A"},"body":{"type":"string","nullable":true,"example":"Ad card body text"},"caption":{"type":"string","nullable":true,"example":"Caption text"},"cta_type":{"type":"string","nullable":true,"example":"SHOP_NOW"},"cta_text":{"type":"string","nullable":true,"example":"Shop Now"},"landing_page":{"type":"string","nullable":true,"example":"https://example.com/variant-a"},"media":{"type":"array","items":{"$ref":"#/components/schemas/PublicAdMedia"}}}},"PublicSpiedBrand":{"type":"object","properties":{"id":{"type":"integer","example":1},"brand_id":{"type":"integer","example":456},"brand_external_id":{"type":"string","example":"2016485295279615"},"brand_name":{"type":"string","nullable":true,"example":"Acme"},"brand_logo_url":{"type":"string","nullable":true,"example":"https://example.com/logo.png"},"status":{"type":"string","example":"1"},"active_ads":{"type":"integer","example":109},"inactive_ads":{"type":"integer","example":23},"videos":{"type":"integer","example":45},"images":{"type":"integer","example":64},"carousels":{"type":"integer","example":23},"created_at":{"type":"string","format":"date-time","example":"2025-01-15T10:30:00+00:00"},"last_spied_at":{"type":"string","format":"date-time","nullable":true,"example":"2025-03-01T14:00:00+00:00"}}},"PublicBoard":{"type":"object","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"Top Performers"},"slug":{"type":"string","example":"top-performers-1"},"ad_count":{"type":"integer","example":25},"is_public":{"type":"boolean","example":true},"public_url":{"type":"string","nullable":true,"example":"https://app.gethookd.ai/share/board/top-performers-1"},"created_at":{"type":"string","format":"date-time","example":"2025-01-15T10:30:00+00:00"},"updated_at":{"type":"string","format":"date-time","example":"2025-03-01T14:00:00+00:00"}}},"PublicCloneAd":{"type":"object","properties":{"id":{"type":"integer","example":1},"title":{"type":"string","example":"Clone of Ad #123"},"created_at":{"type":"string","format":"date-time","example":"2025-03-01T14:00:00+00:00"},"updated_at":{"type":"string","format":"date-time","example":"2025-03-01T14:05:00+00:00"},"prompts":{"type":"array","items":{"$ref":"#/components/schemas/PublicCloneAdPrompt"}}}},"PublicCloneAdPrompt":{"type":"object","properties":{"id":{"type":"integer","example":1},"prompt":{"type":"string","example":"Clone ad #123"},"aspect_ratio":{"type":"string","example":"Square"},"in_progress":{"type":"boolean","example":false},"created_at":{"type":"string","format":"date-time","example":"2025-03-01T14:00:00+00:00"},"media":{"type":"array","items":{"$ref":"#/components/schemas/PublicCloneAdMedia"}}}},"PublicCloneAdMedia":{"type":"object","properties":{"id":{"type":"integer","example":1},"url":{"type":"string","example":"https://example.com/generated-image.png"},"aspect_ratio":{"type":"string","example":"Square"},"is_image_reference":{"type":"boolean","example":false},"order":{"type":"integer","example":1}}},"PublicSavedSearch":{"type":"object","properties":{"id":{"type":"integer","example":42},"user_id":{"type":"integer","example":7},"name":{"type":"string","example":"US winning supplements"},"is_predefine":{"type":"boolean","nullable":true,"example":false},"gender_audience":{"type":"string","nullable":true,"example":"men,women"},"age_audience":{"type":"string","nullable":true,"example":"25-34,35-44"},"ad_spend_range":{"type":"string","nullable":true,"example":"3,4"},"ads_per_brand_limit":{"type":"integer","nullable":true,"example":4},"created_at":{"type":"string","format":"date-time","example":"2026-05-01T10:30:00+00:00"},"updated_at":{"type":"string","format":"date-time","example":"2026-05-01T10:30:00+00:00"},"parent_categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":16},"title":{"type":"string","example":"Health/Wellness"}}}},"languages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":1},"name":{"type":"string","example":"English"}}}},"excluded_brands":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":10},"name":{"type":"string","example":"Acme"}}}},"creative_categories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer","example":2},"title":{"type":"string","example":"Testimonial - Reviews"}}}}}},"PublicSavedSearchInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"The saved search name. Max 120 characters.","example":"US winning supplements","maxLength":120},"parent_categories":{"type":"array","description":"Niche / parent-category IDs. Max 50 items.","maxItems":50,"items":{"type":"integer"},"example":[16,30]},"languages":{"type":"array","description":"Language IDs. Max 20 items.","maxItems":20,"items":{"type":"integer"},"example":[1]},"excluded_brands":{"type":"array","description":"Brand IDs to exclude. Max 100 items.","maxItems":100,"items":{"type":"integer"},"example":[10,11]},"creative_categories":{"type":"array","description":"Creative-category IDs. Max 50 items.","maxItems":50,"items":{"type":"integer"},"example":[2,17]},"gender_audience":{"type":"string","description":"Gender audience filter (CSV). Max 200 characters.","example":"men,women","maxLength":200,"nullable":true},"age_audience":{"type":"string","description":"Age audience filter (CSV). Max 200 characters.","example":"25-34,35-44","maxLength":200,"nullable":true},"ad_spend_range":{"type":"string","description":"Spend buckets (CSV). Max 200 characters.","example":"3,4","maxLength":200,"nullable":true},"ads_per_brand_limit":{"type":"integer","description":"Limit results per brand (1-50).","example":4,"minimum":1,"maximum":50,"nullable":true}}}},"responses":{"Unauthenticated":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Unauthenticated."},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Unauthenticated."}}}}}},"InsufficientCredits":{"description":"","content":{"application/json":{"schema":{"type":"object","example":{"errors":true,"message":"Not enough credits"},"properties":{"errors":{"type":"boolean","example":true},"message":{"type":"string","example":"Not enough credits"}}}}}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Public API team token, passed as `Authorization: Bearer <token>`. Each endpoint additionally requires the token to carry the scope named in its summary (e.g. explore:read, brand-spy:write, swipe-file:write, boards:write, searches:write, clone-ads:write)."}}}}