# Admanage API (llms.txt) > v1 API for managing ad accounts, launching ads, querying reports, browsing media, duplicating campaigns/ad sets/ads, and automating workflows. Base URL: https://api.admanage.ai Versioned base: https://api.admanage.ai/v1 Full docs UI: https://admanage.ai/api-docs ## Authentication Every request (except GET /v1/health and GET /llms.txt) MUST include an Authorization header with a Bearer token. **Header format:** ``` Authorization: Bearer YOUR_API_KEY ``` **Important:** Do NOT use x-api-key or any other header name. The ONLY accepted format is the Authorization header with a Bearer prefix. **Example:** ```bash curl -sS "https://api.admanage.ai/v1/adaccounts" \ -H "Authorization: Bearer ak_N-XqphL3DxvA..." ``` **Common mistakes:** - Using x-api-key: ak_... instead of Authorization: Bearer ak_... (will return 401) - Forgetting the "Bearer " prefix (will return 401) - Using query param ?api_key=... (not supported) API keys are company-scoped — all data returned is automatically filtered to the company associated with the key. If authentication fails, the API returns: ```json { "success": false, "error": { "code": "unauthorized", "message": "Authorization header with Bearer token is required." } } ``` ## Error Shape ```json { "success": false, "error": { "code": "bad_request", "message": "human readable message", "requestId": "req-123" } } ``` ## Pagination All list endpoints use `page` + `limit` query params (default `page=1`, `limit=25`, max `limit=100`) and return: ```json { "data": [...], "pagination": { "page": 1, "limit": 25, "total": 123, "totalPages": 5 } } ``` Results use a **stable sort** — the primary sort key (usually `lastUpdated` or `createdAt` desc) is paired with the unique `id` as a tiebreaker. This means looping `page=1..totalPages` with a fixed `limit` surfaces every row exactly once, even when many rows share the same `lastUpdated`/`createdAt` value (common right after a bulk sync). If rows are being written while you paginate, a row created mid-scan can still shift pages — filter by `accountId`/`campaignId` to narrow the snapshot if that matters. `/v1/reports/query` is the exception: it uses `offset` + `limit` and returns `{ offset, limit, total, hasMore }` instead of `page`/`totalPages`. ## Quick Launch (Fastest Path) To launch an ad in 3 API calls: 1. **GET /v1/launch-defaults** — returns your saved page, insta, display names, copy, CTA, link, UTM tags 2. **GET /v1/adsets?accountId=act_123** — returns ad sets with value/label ready for launch 3. **POST /v1/launch** — launch with defaults + ad sets + media URL, or with a Meta Post ID Then poll **GET /v1/batch-status/:id** until complete. Meta identity rule: pass `page` and `insta` as raw ID strings from `GET /v1/launch-defaults` or `GET /v1/profiles`. Also pass `facebookName` and `instaName` when available so AdManage can display readable profile chips. Do not pass profile objects like `{ "id": "..." }`. Example (uses defaults — only need media + ad sets): ```bash # Step 1: Get defaults curl -sS "https://api.admanage.ai/v1/launch-defaults" -H "Authorization: Bearer " # Step 2: Get ad sets curl -sS "https://api.admanage.ai/v1/adsets?accountId=act_384730851257635&limit=10" -H "Authorization: Bearer " # Step 3: Launch (fill in defaults from step 1, ad sets from step 2) curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [{ "adAccountId": "act_384730851257635", "title": "Stop wasting time on ad management", "description": "Launch ads 10x faster with AdManage", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "page": "470703006115773", "facebookName": "Admanage", "insta": "17841471826052348", "instaName": "admanage.official", "adSets": [{ "value": "120248289622780456", "label": "US Broad 25-44" }], "media": [{ "url": "https://media.admanage.ai/acme/creative.mp4" }] }] }' # Step 4: Poll until done curl -sS "https://api.admanage.ai/v1/batch-status/9912" -H "Authorization: Bearer " ``` ## Health - GET /v1/health Sample: ```bash curl -sS https://api.admanage.ai/v1/health ``` Response: ```json { "success": true, "status": "ok", "db": "ok" } ``` ## Launch Creates an ad batch and dispatches to the launcher service. Returns immediately with batch ID for async polling. Supported via POST /v1/launch: facebook (Meta), tiktok, snapchat, pinterest, axon (AppLovin), taboola, linkedin, reddit. Google Ads uses the dedicated POST /v1/google-ads/launch endpoint documented later in this file. - POST /v1/launch Body: { ads: [...] } Each ad is fully self-contained with its own platform, account, ad sets, and media. ### ads[] fields | Field | Required | Description | |-------|----------|-------------| | adName | no | Custom ad name | | adAccountId | yes | Ad account ID (e.g. "act_123" for Meta, numeric for TikTok/Pinterest/Axon/LinkedIn/Reddit, UUID for Snapchat, provider-specific string for Taboola) | | workspaceId | no | Workspace ID for token lookup | | platform | no | "facebook", "tiktok", "snapchat", "pinterest", "axon", "taboola", "linkedin", or "reddit". Auto-detected from adAccountId (act_* = facebook, UUID = snapchat) or adSets if omitted | | title | no | Headline / primary text | | description | no | Body text | | adDescription | no | Additional description | | cta | no | Call-to-action: "LEARN_MORE", "SHOP_NOW", "SIGN_UP", etc. | | link | no | Landing page URL | | displaylink | no | Display link shown on ad | | urlTags | no | UTM parameters appended to link | | page | Meta only | Facebook Page ID string to post from. Required for Meta. Use "470703006115773", not { "id": "470703006115773" } | | insta | Meta only | Instagram account ID string. Required for Meta unless the selected page is explicitly used as the Instagram identity | | adSets | yes | Array of ad sets to launch into (from GET /v1/adsets) | | media | yes, except existing-post/code flows | Array of media objects (videos or images). May be omitted for Meta Post ID ads, TikTok Spark codes, Meta partnership codes, and other documented existing-post flows | | type | no | "single", "multi", "carousel", "flexible" (default "single") | | launchPaused | no | Set true to create launched ads in PAUSED status instead of ACTIVE when supported. Can be set per ad; top-level launchPaused is also copied into simplified rows | | effectiveStoryId | Meta Post ID ads | Existing Meta Post ID / object_story_id in `pageId_postId` format. Creates the ad from the existing post and preserves engagement. Preferred field name | | postId | Meta Post ID ads | Alias for `effectiveStoryId`; use `pageId_postId` format | | objectStoryId / object_story_id / effective_object_story_id | Meta Post ID ads | Aliases for `effectiveStoryId` | | scalePostId | Meta only | Existing-post reuse toggle. Automatically enabled when a Post ID field is supplied | | instagramPostUrl | Meta only | Instagram `/p/`, `/reel/`, or `/tv/` permalink to boost as an existing organic post. The API resolves the post, pulls caption/media, and enables Post ID reuse | | instagramPostUrls | Meta only | Multiple Instagram permalinks to boost. Each URL becomes its own draft/launch row | | showProducts | Meta only | Convenience alias for manual catalogue/product extensions. Set true with catalogueId and productSetId to add "Show Products" to normal/multi-attached creatives | | catalogueAdConfig | Meta only | Full catalogue ads config object. Use for automatic Advantage+ catalogue ads, Hunch-style local-inventory single-image catalog ads, or manual "Show Products" product extensions | | catalogueId / catalogId | Meta only | Product catalog ID. Used by flat catalogue fields; maps to catalogueAdConfig.selectedCatalogue.id | | catalogueName / catalogName | Meta only | Product catalog display name | | productSetId | Meta only | Product set ID. Required for manual Show Products; automatic mode can resolve all-products when omitted | | productSetName | Meta only | Product set display name | | catalogueAdFormatMode | Meta only | "manual" for Show Products on supplied creatives, or "automatic" for Advantage+ catalog creative generation | | catalogueAdFormat | Meta only | "SINGLE_IMAGE", "SINGLE_VIDEO", "CAROUSEL", or "COLLECTION" | | catalogueAdLocalInventorySingleImage / catalogAdLocalInventorySingleImage / localInventorySingleImage | Meta only | Automatic catalog mode flag for the Hunch-style/local-inventory single-image payload. Use with `catalogueAdFormatMode: "automatic"` and `catalogueAdFormat: "SINGLE_IMAGE"` | | includeCarouselForCatalogue | Meta only | Manual mode toggle for product carousel extensions. Defaults to true when Show Products is enabled | | sparkCode | TikTok only | TikTok Spark Ads auth code. Launches from the creator's organic post — identity and post are resolved server-side. media is optional when set. | | partnershipCode | Meta only | Meta partnership ad code (e.g. "adcode-..."). Launches a branded-content / partnership ad from the creator's post. media is optional when set; still pass page and insta. | | selectedTikTokUserAccount | TikTok only | TikTok identity for ad attribution | | axonEndCards | Axon only | End card configuration | | axonDestinationUrl | Axon only | Destination URL used by the Axon launcher | | axonUrlTags | Axon only | Axon URL tags | | snapchatBrandName | Snapchat only | Brand name for Snapchat creatives | | snapchatProfileId | Snapchat only | Public profile ID | | pinterestBoardId | Pinterest only | Board ID for pin creation | | linkedinHeadline | LinkedIn only | LinkedIn headline override | | linkedinDescription | LinkedIn only | LinkedIn intro text override | | linkedinCTA | LinkedIn only | LinkedIn CTA label | | linkedinAdFormat | LinkedIn only | "SINGLE_IMAGE", "VIDEO", or "CAROUSEL" | | linkedinObjective | LinkedIn only | Objective type such as WEBSITE_VISITS or LEAD_GENERATION | | carouselCards | LinkedIn carousel only | Array of { headline, landingUrl, imageUrn? } cards | | redditHeadline | Reddit only | Reddit headline override | | redditText | Reddit only | Reddit body text override | | redditCTA | Reddit only | Reddit CTA label | | redditAdType | Reddit only | "TEXT", "VIDEO", "IMAGE", or "CAROUSEL" (matches Reddit API) | | subreddit | Reddit only | Target subreddit when required by account setup | | taboolaCampaignAction | Taboola only | "existing" or "create" | | taboolaCampaignIds | Taboola only | Existing campaign IDs for launch | | taboolaCampaignNames | Taboola only | Existing campaign names for launch | | taboolaCta | Taboola only | Taboola CTA override | ### adSets[] shape These come from GET /v1/adsets. Pass the objects returned by that endpoint. Minimum required fields: ```json { "value": "120248289622780456", "label": "US Broad 25-44" } ``` ### media[] shape Just provide the public URL — type and name are auto-derived from the filename extension: ```json { "url": "https://media.admanage.ai/admanage.ai/ERER_DE_red123D4kWzVhn.mp4" } ``` You can optionally include any of these fields: ```json { "url": "https://media.admanage.ai/admanage.ai/ERER_DE_red123D4kWzVhn.mp4", "name": "creative-1.mp4", "type": "video", "thumbnail": "https://media.admanage.ai/admanage.ai/thumb-ERER_DE_red123D4kWzVhn.jpg", "existingPostUrn": "urn:li:share:123456789", "portraitVariation": { "url": "https://media.admanage.ai/admanage.ai/card-1-story.png", "name": "card-1-story.png", "type": "image", "width": 1080, "height": 1920 } } ``` Auto-detection: .mp4/.mov/.avi/.webm = video, .png/.jpg/.gif/.webp = image. Note: `videos` is accepted as an alias for `media`. For Meta carousel cards, `portraitVariation` supplies a vertical/Reels/Stories placement variant for that card. It accepts the same media fields as the parent item; `url` is normalized to `preview` before launch. For Meta Post ID ads, omit `media` and pass `effectiveStoryId` (preferred) or `postId` at the ad level: ```json { "effectiveStoryId": "470703006115773_122123456789012345" } ``` You may also put the Post ID on a media item instead of `url`: ```json { "object_story_id": "470703006115773_122123456789012345" } ``` For Instagram post/reel URL boosts, pass `instagramPostUrl` or `instagramPostUrls` at the ad level instead of uploading media: ```json { "instagramPostUrl": "https://www.instagram.com/reel/BoostMe_123/" } ``` Supported URL shapes are `instagram.com/p/{shortcode}`, `instagram.com/reel/{shortcode}`, and `instagram.com/tv/{shortcode}`. The permalink must belong to the selected/default connected Instagram account and be found in its latest 500 Graph media posts. You can also paste a supported Instagram post URL as `media[].url`. Common Meta launch mistakes: - `page` and `insta` must be ID strings, not objects. - Carousel media items must each include `carouselTitle`. - If you want ads created paused, set `launchPaused: true` on each ad or at the top level of the simplified payload. - For Post ID ads, use `pageId_postId` format and do not upload the post media separately. - For Instagram post URL boosts, pass the permalink from the selected/default connected Instagram account and do not download/re-upload the media. - For Show Products, use `showProducts: true` with `catalogueId` and `productSetId`, or pass the full `catalogueAdConfig`. - For Hunch-style catalog lead ads, use automatic catalogue mode with `format: "SINGLE_IMAGE"`, `localInventorySingleImage: true`, `media: []`, and a lead-form CTA. ### Example: Meta (Facebook/Instagram) Launch ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "Spring Sale - UGC", "adAccountId": "act_384730851257635", "workspaceId": "workspace_abc", "title": "Stop wasting time on ad management", "description": "Launch ads 10x faster with AdManage", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "displaylink": "admanage.ai", "urlTags": "utm_source=facebook&utm_medium=paid", "page": "470703006115773", "insta": "17841471826052348", "adSets": [ { "value": "120248289622780456", "label": "US Broad 25-44" } ], "media": [ { "url": "https://media.admanage.ai/acme/Spring-Sale-UGC.mp4" } ] }, { "adName": "Spring Sale - Product Demo", "adAccountId": "act_384730851257635", "workspaceId": "workspace_abc", "title": "Stop wasting time on ad management", "description": "Launch ads 10x faster with AdManage", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "page": "470703006115773", "insta": "17841471826052348", "adSets": [ { "value": "120248289622780456", "label": "US Broad 25-44" } ], "media": [ { "url": "https://media.admanage.ai/acme/Product-Demo.mp4" } ] } ] }' ``` ### Example: Meta Post ID Launch Creates an ad from an existing Facebook/Instagram post and preserves engagement. No media upload is needed. ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "Spring Sale - Existing Post", "adAccountId": "act_384730851257635", "workspaceId": "workspace_abc", "effectiveStoryId": "470703006115773_122123456789012345", "page": "470703006115773", "insta": "17841471826052348", "launchPaused": true, "adSets": [ { "value": "120248289622780456", "label": "US Broad 25-44" } ] } ] }' ``` ### Example: Meta Instagram Post URL Boost Creates an ad from an existing organic Instagram post/Reel permalink. No media upload is needed. ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "Spring Sale - Existing IG Reel", "adAccountId": "act_384730851257635", "workspaceId": "workspace_abc", "instagramPostUrl": "https://www.instagram.com/reel/BoostMe_123/", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "page": "470703006115773", "insta": "17841471826052348", "launchPaused": true, "adSets": [ { "value": "120248289622780456", "label": "US Broad 25-44" } ] } ] }' ``` ### Example: TikTok Launch ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "TikTok - Creator Testimonial", "platform": "tiktok", "adAccountId": "7486153503963054097", "workspaceId": "workspace_abc", "title": "Check this out", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "adSets": [ { "value": "1857570827480306", "label": "Prospecting Ad Group" } ], "media": [ { "url": "https://media.admanage.ai/acme/ugc-creator-testimonial.mp4" } ] } ] }' ``` ### Example: TikTok Spark Ads (spark code) Launch Launch straight from a creator-shared Spark Ads auth code — no media upload needed. ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "TikTok Spark - Creator Post", "platform": "tiktok", "adAccountId": "7486153503963054097", "workspaceId": "workspace_abc", "sparkCode": "TTAUTHCODE_abc123...", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "adSets": [ { "value": "1857570827480306", "label": "Prospecting Ad Group" } ] } ] }' ``` ### Example: Meta Partnership Code Launch Launch a branded-content / partnership ad from a creator-shared partnership ad code — no media upload needed. ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "Meta Partnership - Creator Collab", "adAccountId": "act_384730851257635", "workspaceId": "workspace_abc", "partnershipCode": "adcode-abc123def456...", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "page": "470703006115773", "insta": "17841471826052348", "adSets": [ { "value": "120248289622780456", "label": "US Broad 25-44" } ] } ] }' ``` ### Example: Snapchat Launch ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "Snap - Creative 1", "adAccountId": "b975c7e6-7e3a-477f-b6c9-9e83b73e8109", "workspaceId": "workspace_abc", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "adSets": [ { "value": "4dc89846-99ca-4bd2-8806-180d1f137f0a", "label": "Landing Page Views Ad Set" } ], "media": [ { "url": "https://media.admanage.ai/acme/snap-creative.png" } ] } ] }' ``` ### Example: Pinterest Launch ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "Pinterest - Spring Collection", "platform": "pinterest", "adAccountId": "549769890977", "workspaceId": "workspace_abc", "title": "Spring collection", "description": "Shop our new arrivals", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "adSets": [ { "value": "2680088752242", "label": "Awareness Ad Group" } ], "media": [ { "url": "https://media.admanage.ai/acme/pin-creative.png" } ] } ] }' ``` ### Example: Axon Launch ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "Axon - Creative 1", "platform": "axon", "adAccountId": "1159321785", "workspaceId": "workspace_abc", "axonDestinationUrl": "https://admanage.ai/", "axonUrlTags": "utm_source=axon&utm_medium=paid", "cta": "LEARN_MORE", "axonEndCards": [ { "id": "endcard-1", "name": "Default End Card" } ], "adSets": [], "media": [ { "url": "https://media.admanage.ai/acme/axon-creative.mp4" } ] } ] }' ``` ### Example: LinkedIn Launch ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "LinkedIn - Video 1", "platform": "linkedin", "adAccountId": "513994704", "workspaceId": "workspace_abc", "title": "See what AdManage can automate", "description": "Launch and monitor paid social from one workflow.", "cta": "LEARN_MORE", "linkedinCTA": "LEARN_MORE", "link": "https://admanage.ai/", "adSets": [ { "value": "657885514", "label": "Website Visits Test" } ], "media": [ { "url": "https://media.admanage.ai/acme/linkedin-creative.mp4", "type": "video" } ] } ] }' ``` ### Example: Reddit Launch ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "Reddit - Video 1", "platform": "reddit", "adAccountId": "123456789", "workspaceId": "workspace_abc", "title": "See what AdManage can automate", "description": "Launch and monitor paid social from one workflow.", "cta": "LEARN_MORE", "subreddit": "marketing", "link": "https://admanage.ai/", "adSets": [ { "value": "adgroup-123", "label": "Reddit Test Ad Group" } ], "media": [ { "url": "https://media.admanage.ai/acme/reddit-creative.mp4", "type": "video" } ] } ] }' ``` ### Example: Taboola Launch ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [ { "adName": "Taboola - Existing Campaign", "platform": "taboola", "adAccountId": "taboolaaccount-cedadmanageai", "workspaceId": "workspace_abc", "title": "Read the full guide", "description": "Launch Taboola items from AdManage", "link": "https://admanage.ai/", "taboolaCampaignAction": "existing", "taboolaCampaignIds": ["campaign-123"], "taboolaCampaignNames": ["Main Campaign"], "taboolaCta": "LEARN_MORE", "media": [ { "url": "https://media.admanage.ai/acme/taboola-creative.jpg" } ] } ] }' ``` ### Launch Response (all platforms, 202 Accepted) ```json { "success": true, "message": "Ad launch initiated successfully", "adBatchSlug": "a1b2c3d4", "adBatchId": 9912, "isAsync": true } ``` After launching, poll GET /v1/batch-status/{adBatchId} until status is "success" or "error". ### Legacy format The old `creativeState` wrapper format is still fully supported: ```json { "creativeState": { "globalDefaults": { ... }, "rows": [ ... ] } } ``` ### Re-launch an existing batch - POST /v1/launch/from-draft Body: { batchId } ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch/from-draft" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"batchId": 9911}' ``` Response (202): ```json { "success": true, "message": "Ad launch initiated from draft", "adBatchSlug": "batch-abc123", "adBatchId": 9911, "isAsync": true } ``` ### Check Launch Batch Status Poll this endpoint after launching to track progress. - GET /v1/batch-status/:id Top-level `success` means the API request succeeded (auth OK). Use `batchSucceeded` and `summaryStatus` for whether the batch itself completed successfully. Per-ad Meta errors appear in `message`, `error`, `failedDetails`, and each `ads[]` item's `errorMessage` when available. ```bash curl -sS "https://api.admanage.ai/v1/batch-status/9911" \ -H "Authorization: Bearer " ``` ```json { "success": true, "batchSucceeded": false, "status": "processing", "summaryStatus": "in_progress", "progress": 62, "totalAds": 20, "successfulAds": 12, "failedAds": [], "message": "Launching..." } ``` ## Accounts + Profiles - GET /v1/adaccounts Query: page, limit ```bash curl -sS "https://api.admanage.ai/v1/adaccounts?page=1&limit=25" \ -H "Authorization: Bearer " ``` ```json { "data": [ { "id": 101, "accountId": "act_123456789", "accountName": "Main Account", "businessId": "act_123456789", "businessName": "Acme Holdings", "workspaceId": "workspace_abc", "company": "acme", "type": "facebook", "updatedAt": "2026-02-18T08:25:12.000Z" } ], "pagination": { "page": 1, "limit": 25, "total": 1, "totalPages": 1 } } ``` - GET /v1/profiles Returns Facebook Pages, Instagram accounts, and Threads profiles associated with your ad account. Use the `pageId` values as the `page` (Facebook) and `insta` (Instagram) fields when launching ads. Query parameters: | Param | Required | Description | |-------|----------|-------------| | businessId | no | Ad account ID (e.g. "act_123"). If omitted, returns all profiles for your company | | workspaceId | no | Workspace ID. Auto-discovered from ad account if omitted | | type | no | Filter by type: "facebook", "instagram", or "threads" | | refresh | no | Set to "true" to bypass DB cache and fetch live from Facebook Graph API | ```bash # List all profiles (simplest — no params needed) curl -sS "https://api.admanage.ai/v1/profiles" \ -H "Authorization: Bearer " # Filter by ad account curl -sS "https://api.admanage.ai/v1/profiles?businessId=act_123" \ -H "Authorization: Bearer " # Filter by type curl -sS "https://api.admanage.ai/v1/profiles?businessId=act_123&type=facebook" \ -H "Authorization: Bearer " # Force refresh from Facebook Graph API curl -sS "https://api.admanage.ai/v1/profiles?businessId=act_123&refresh=true" \ -H "Authorization: Bearer " ``` Use the `pageId` from facebook profiles as the `page` field and `pageName` as `facebookName` in launch requests. Use the `pageId` from instagram profiles as the `insta` field and `pageName` as `instaName` in launch requests. ```json { "success": true, "data": { "profiles": [ { "pageId": "470703006115773", "pageName": "Acme Brand Page", "type": "facebook", "pagePicture": "https://scontent.xx.fbcdn.net/...", "businessId": "act_123456789", "workspaceId": "workspace_abc" }, { "pageId": "17841405999999999", "pageName": "acme.official", "type": "instagram", "pagePicture": "https://scontent.xx.fbcdn.net/...", "businessId": "act_123456789", "workspaceId": "workspace_abc", "relatedPageId": "470703006115773", "followers": 15200 } ], "grouped": { "facebook": [ { "pageId": "470703006115773", "pageName": "Acme Brand Page", "..." : "..." } ], "instagram": [ { "pageId": "17841405999999999", "pageName": "acme.official", "..." : "..." } ], "threads": [] }, "counts": { "facebook": 1, "instagram": 1, "threads": 0 } } } ``` - GET /v1/user/extended2 ```bash curl -sS https://api.admanage.ai/v1/user/extended2 \ -H "Authorization: Bearer " ``` ```json { "id": "usr_01HXYZABCDEF", "email": "user@acme.com", "name": "Acme Operator", "company": "acme", "organizations": [ { "id": "org_123", "name": "Acme Holdings", "role": "admin" } ], "workspaces": [ { "id": "workspace_abc", "name": "Main Workspace", "defaultAdAccountId": "act_123456789" } ], "settings": { "timezone": "America/Los_Angeles", "currency": "USD" } } ``` - GET /v1/workspaces Query: page, limit ```bash curl -sS "https://api.admanage.ai/v1/workspaces?page=1&limit=25" \ -H "Authorization: Bearer " ``` ```json { "data": [ { "id": "workspace_abc", "name": "Main Workspace", "company": "acme", "organizationId": "org_123", "metaAccountId": 12, "tiktokAccountId": null, "adAccounts": [ { "accountId": "act_123456789", "accountName": "Main Account", "platform": "facebook" } ] } ], "pagination": { "page": 1, "limit": 25, "total": 1, "totalPages": 1 } } ``` ## Templates - GET /v1/templates/ad-copy Query: page, pageSize, organizationId, businessId, adAccountId, includeTotal (default true; pass false for faster list responses) ```bash curl -sS "https://api.admanage.ai/v1/templates/ad-copy?page=1&pageSize=10" \ -H "Authorization: Bearer " ``` ```json { "data": [ { "id": "copy_abcd1234", "name": "UGC Static Template", "defaultTitle": "Free Trial", "defaultDescription": "Try it today", "businessId": "act_123456789", "workspaceId": "workspace_abc", "updatedAt": "2026-02-18T08:25:12.000Z" } ], "pagination": { "page": 1, "pageSize": 10, "total": 1, "totalPages": 1 } } ``` - GET /v1/templates/ad-copy/:id Query: organizationId, businessId, adAccountId ```bash curl -sS "https://api.admanage.ai/v1/templates/ad-copy/copy_abc" \ -H "Authorization: Bearer " ``` ```json { "id": "copy_abcd1234", "name": "UGC Static Template", "businessId": "act_123456789", "workspaceId": "workspace_abc", "templateData": { "globalDefaults": { "title": "Spring Launch", "description": "Top-performing variants", "cta": "SHOP_NOW" }, "rows": [ { "adName": "Creative 1", "headline": "New collection", "description": "Shop now", "videos": ["https://media.admanage.ai/example/ad-1.mp4"] } ] } } ``` ## Performance (Campaigns + Ad Sets) Retrieve campaign and ad set structures from your ad accounts. Data is synced from ad platforms — use these to discover IDs for launching, duplicating, or querying reports. ### Typical workflow 1. GET /v1/adaccounts → find your accountId (e.g. "act_384730851257635") and workspaceId 2. GET /v1/profiles?businessId=act_384730851257635 → get Facebook Page IDs (`page`) and Instagram IDs (`insta`) 3. GET /v1/campaigns?accountId=act_384730851257635 → list campaigns, get campaignId 4. GET /v1/adsets?campaignId=120247699100220456 → list ad sets in that campaign, get adSetId 5. POST /v1/launch → launch with page, insta, adSets, and media 6. GET /v1/reports/query?accountIds=act_384730851257635&metrics=spend,impressions,clicks → ad-level performance data ### GET /v1/campaigns List campaigns aggregated from ad sets. Campaigns are grouped from ad set records, so totalSpend and adSetCount reflect what's stored in AdManage. For TikTok accounts with no ad sets synced into AdManage (e.g. reporting-only API consumers), the authoritative campaign list is fetched live from TikTok — those rows carry campaign metadata (id, name, status, objective) with totalSpend/adSetCount of 0; use GET /v1/reports/query for spend. Query parameters: | Param | Required | Description | |-------|----------|-------------| | page | no | Page number (default 1) | | limit | no | Results per page, max 100 (default 25) | | accountId | no | Filter by ad account ID (also accepts adAccountId) | | platform | no | Filter by platform: "facebook", "tiktok", "pinterest", "snapchat", "axon", "taboola", "linkedin", "reddit", "google_ads" | | status | no | Filter by campaign status: "ACTIVE", "PAUSED", etc. | ```bash curl -sS "https://api.admanage.ai/v1/campaigns?page=1&limit=25&accountId=act_384730851257635" \ -H "Authorization: Bearer " ``` Response fields: | Field | Type | Description | |-------|------|-------------| | campaignId | string | Facebook/TikTok/Pinterest campaign ID | | campaignName | string | Campaign name | | platform | string | "facebook", "tiktok", "pinterest", "snapchat" | | accountId | string | Ad account ID (e.g. "act_384730851257635") | | status | string | Campaign status ("ACTIVE", "PAUSED", "DELETED", "ARCHIVED") | | totalSpend | number | Sum of spend across all ad sets in this campaign | | adSetCount | number | Number of ad sets in this campaign | | lastUpdated | string | ISO datetime of most recent ad set update | ```json { "data": [ { "campaignId": "120247699100220456", "campaignName": "Q1 Prospecting - Broad", "platform": "facebook", "accountId": "act_384730851257635", "status": "ACTIVE", "totalSpend": 842.22, "adSetCount": 4, "lastUpdated": "2026-02-19T21:12:45.787Z" }, { "campaignId": "120248100500330456", "campaignName": "Retargeting - Website Visitors", "platform": "facebook", "accountId": "act_384730851257635", "status": "ACTIVE", "totalSpend": 312.50, "adSetCount": 2, "lastUpdated": "2026-02-18T14:30:00.000Z" } ], "pagination": { "page": 1, "limit": 25, "total": 2, "totalPages": 1 } } ``` ### GET /v1/adsets List ad sets with status, spend, and ad count. Filter by campaign to drill into a specific campaign's ad sets. Query parameters: | Param | Required | Description | |-------|----------|-------------| | page | no | Page number (default 1) | | limit | no | Results per page, max 100 (default 25) | | campaignId | no | Filter by campaign ID | | accountId | no | Filter by ad account ID (also accepts adAccountId) | | workspaceId | no | Filter by workspace ID — resolves to the workspace's ad accounts | | platform | no | Filter by platform | | status | no | Filter by ad set status | ```bash curl -sS "https://api.admanage.ai/v1/adsets?campaignId=120247699100220456&limit=25" \ -H "Authorization: Bearer " ``` Response fields: | Field | Type | Description | |-------|------|-------------| | id | number | Internal AdManage ad set ID | | adSetId | string | Platform ad set ID (use this for duplication/delete) | | name | string | Ad set name | | value | string | Same as adSetId — launch-ready alias for ads[].adSets[].value | | label | string | Same as name — launch-ready alias for ads[].adSets[].label | | campaignId | string | Parent campaign ID | | campaignName | string | Parent campaign name | | account_id | string | Ad account ID (with act_ prefix for Meta) | | platform | string | "facebook", "tiktok", "pinterest", "snapchat" | | status | string | Ad set status ("ACTIVE", "PAUSED", etc.) | | campaignStatus | string | Parent campaign status | | adSpend | number | Total spend for this ad set | | adCount | number | Number of ads in this ad set | | lastUpdated | string | ISO datetime of last update | **Tip:** Each ad set object includes `value` and `label` fields, so you can pass them directly into `ads[].adSets[]` when launching. ```json { "data": [ { "id": 4521, "adSetId": "120248289622780456", "name": "US Broad - Women 25-44", "value": "120248289622780456", "label": "US Broad - Women 25-44", "campaignId": "120247699100220456", "campaignName": "Q1 Prospecting - Broad", "account_id": "act_384730851257635", "platform": "facebook", "status": "ACTIVE", "campaignStatus": "ACTIVE", "adSpend": 214.11, "adCount": 8, "lastUpdated": "2026-02-19T21:12:45.787Z" } ], "pagination": { "page": 1, "limit": 25, "total": 2, "totalPages": 1 } } ``` ### GET /v1/manage/list-ads List ads in a Facebook ad set or ad account directly from the Graph API. Use this to see which ads exist before deleting or editing them. Query parameters: | Param | Required | Description | |-------|----------|-------------| | adSetId | no* | Ad set ID to list ads from | | accountId | no* | Ad account ID (e.g. act_123) to list all ads | | status | no | Filter by effective status: "ACTIVE", "PAUSED", "ARCHIVED", "DELETED" | | limit | no | Max results (default 50, max 200) | | workspaceId | no | Workspace ID for token lookup | *Either adSetId or accountId is required. ```bash curl -sS "https://api.admanage.ai/v1/manage/list-ads?adSetId=120248289622780456&limit=50" \ -H "Authorization: Bearer " ``` Response: ```json { "success": true, "data": [ { "id": "120249137908810789", "name": "Video Ad - US Broad", "status": "ACTIVE", "effectiveStatus": "ACTIVE", "createdTime": "2026-02-18T08:25:12+0000", "thumbnailUrl": "https://..." } ], "count": 12 } ``` ## Batches - GET /v1/adbatches Query: page, limit, search, status, channel, user, adAccountId, workspaceId, privateHistory, dateFrom, dateTo ```bash curl -sS "https://api.admanage.ai/v1/adbatches?page=1&limit=25&adAccountId=act_123" \ -H "Authorization: Bearer " ``` ```json { "data": [ { "id": 9911, "slug": "batch_2026_02_18_9911", "status": "processing", "user": "user@acme.com", "workspaceId": "workspace_abc", "adAccountId": "act_123456789", "createdAt": "2026-02-18T08:25:12.000Z", "updatedAt": "2026-02-18T08:28:41.000Z" } ], "pagination": { "page": 1, "limit": 25, "total": 1, "totalPages": 1 } } ``` - GET /v1/adbatches/:id ```bash curl -sS "https://api.admanage.ai/v1/adbatches/9911" \ -H "Authorization: Bearer " ``` ```json { "id": 9911, "slug": "batch_2026_02_18_9911", "status": "processing", "workspaceId": "workspace_abc", "adAccountId": "act_123456789", "batchData": { "creativeState": { "globalDefaults": { "title": "Spring Launch", "description": "Top-performing variants", "cta": "SHOP_NOW" }, "rows": [ { "adName": "Creative 1", "headline": "New collection" } ] } } } ``` - GET /v1/adbatches/:id/ad-delivery-statuses Query: refresh (optional, "true" to bypass cache) Check the Meta delivery status of each ad in a completed batch. Returns effective_status (ACTIVE, PENDING_REVIEW, WITH_ISSUES, CAMPAIGN_PAUSED, etc.) for every ad. Results are persisted to the database. If all ads are in a terminal state (ACTIVE, PAUSED, DISAPPROVED, etc.), allSettled=true and cached permanently. If some ads are still pending, results are cached for 2 minutes before re-fetching. Every response also includes the launch-stage error context (`batchStatus`, `summaryStatus`, `launchError`, `launchFailedDetails`, `launchErrorMessage`, `finalMessage`) so callers can see when the batch failed before any ads were created — e.g. a Meta video-upload error — instead of getting an empty `adDeliveryStatuses` map. ```bash curl -sS "https://api.admanage.ai/v1/adbatches/9911/ad-delivery-statuses" \ -H "Authorization: Bearer " ``` ```json { "success": true, "batchId": 9911, "adDeliveryStatuses": { "120250610776790456": { "effectiveStatus": "ACTIVE", "status": "ACTIVE", "configuredStatus": "ACTIVE", "issuesInfo": [], "checkedAt": "2026-03-30T12:00:00.000Z" } }, "allSettled": true, "fromCache": false, "checkedAt": "2026-03-30T12:00:00.000Z", "batchStatus": "success", "summaryStatus": "success", "launchError": null, "launchFailedDetails": null, "launchErrorMessage": null, "finalMessage": "5 ads launched" } ``` When a batch fails at the launch stage (e.g. video upload error) and no ads are created, the response surfaces the real error: ```json { "success": true, "batchId": 475476, "adDeliveryStatuses": {}, "fromCache": false, "message": "No videos uploaded or reused: Facebook API Error: Unable to fetch video file from URL. (Code: 389)", "batchStatus": "error", "summaryStatus": "error", "launchError": [{ "message": "No videos uploaded or reused: Facebook API Error: ..." }], "launchFailedDetails": null, "launchErrorMessage": "No videos uploaded or reused: Facebook API Error: Unable to fetch video file from URL. (Code: 389)", "finalMessage": "0 ads completed" } ``` - GET /v1/launch/batch/:batchId Same as batch-status: top-level `success` is the HTTP/API call; `batchSucceeded` reflects whether the launch batch finished without errors. `results.successful` lists only successful rows from stored launch data (failed rows are in `results.failed`). ```bash curl -sS "https://api.admanage.ai/v1/launch/batch/9911" \ -H "Authorization: Bearer " ``` ```json { "success": true, "batchSucceeded": false, "batch": { "id": 9911, "status": "processing", "progress": { "total": 20, "processed": 12, "successful": 11, "failed": 1, "percentage": 60 }, "alreadyProcessing": false } } ``` ## Reports (Ad Performance Data) Query ad performance data across platforms. Uses BigQuery for Facebook, falls back to platform-specific APIs for TikTok and Pinterest. Each row represents one ad (or grouped entity), with the metrics you requested. ### GET /v1/reports/query The main reporting endpoint. Returns ad-level performance data with thumbnails. Query parameters: | Param | Required | Description | |-------|----------|-------------| | accountIds | yes | Comma-separated ad account IDs. Meta IDs use the act_ prefix ("act_384730851257635"); TikTok and Google Ads IDs are plain numbers with no prefix (e.g. "1234567890"). Mix platforms in one query: "act_384730851257635,1234567890". Call GET /v1/adaccounts to discover the exact IDs for every platform you've connected. | | startDate | yes | Start date (YYYY-MM-DD) | | endDate | yes | End date (YYYY-MM-DD) | | metrics | yes | Comma-separated metric names (see below) | | groupBy | no | Dimension to group by (default: "adId"). Options: adId, adName, campaignName, adsetName, landingPage, assetType, creative, videoAsset, imageAsset, body, title, callToActionType, adStatus, objective | | sortBy | no | Metric to sort by (e.g. "spend", "impressions") | | sortDirection | no | "ASC" or "DESC" (default DESC) | | limit | no | Max rows per page (default 25, max 500). Use offset to page beyond one response — pagination.total and hasMore reflect the full result set. | | offset | no | Skip rows for pagination (default 0) | | filters | no | JSON-encoded filters array (see filter operators below) | | filterOperator | no | "AND" or "OR" — how multiple filters combine (default "AND") | | excludePatterns | no | Comma-separated patterns to strip from ad names when grouping (e.g. "- Copy,- v2") | | workspaceId | no | Workspace ID for token resolution (TikTok/Pinterest) | Common metrics (performance): - spend, impressions, clicks, reach, outboundClicks, linkClicks, landingPageViews, results Common metrics (calculated): - cpm, ctr, clicksCost (CPC), frequency, costPerResult, roas Video metrics: - videoViews (3s), thruPlays (15s), videoP025Watched, videoP050Watched, videoP075Watched, videoP100Watched - hookRate (3s views / impressions), vtr (100% watched / impressions), holdPlay (thruPlays / 3s views) Conversion metrics: - purchases, purchaseValue, purchaseRoas, addToCart, registrations, leads, contentViews, appInstalls Use GET /v1/reports/fields for the complete list with descriptions. ```bash curl -sS "https://api.admanage.ai/v1/reports/query?accountIds=act_384730851257635&startDate=2026-02-01&endDate=2026-02-20&metrics=spend,impressions,clicks,ctr,cpm,reach,videoViews,hookRate,purchases,purchaseValue,roas,costPerResult&groupBy=adId&sortBy=spend&sortDirection=DESC&limit=10" \ -H "Authorization: Bearer " ``` Response fields per row: | Field | Type | Description | |-------|------|-------------| | adId | string | Ad ID (or grouped dimension value) | | adName | string | Ad name (included automatically) | | campaignName | string | Parent campaign name | | adsetName | string | Parent ad set name | | thumbnailUrl | string | Creative thumbnail URL | | _accountId | string | Ad account ID this row belongs to | | spend | number | Total amount spent | | impressions | number | Total impressions | | clicks | number | Total clicks | | ctr | number | Click-through rate (clicks / impressions) | | cpm | number | Cost per mille (spend / impressions * 1000) | | (other metrics) | number | As requested in the metrics parameter | ```json { "success": true, "data": [ { "adId": "120247682651440456", "adName": "UGC Creator Testimonial - v2", "campaignName": "Q1 Prospecting - Broad", "adsetName": "US Broad - Women 25-44", "thumbnailUrl": "https://files.admanage.app/act_384730851257635/120247682651440456", "_accountId": "act_384730851257635", "spend": 192.06, "impressions": 46650, "clicks": 492, "ctr": 0.01054, "cpm": 4.117, "reach": 38200, "videoViews": 12800, "hookRate": 0.274, "purchases": 8, "purchaseValue": 640.00, "roas": 3.33, "costPerResult": 24.01 }, { "adId": "120247704303600456", "adName": "Product Demo - Spring Collection", "campaignName": "Q1 Prospecting - Broad", "adsetName": "US Broad - Men 25-54", "thumbnailUrl": "https://files.admanage.app/act_384730851257635/120247704303600456", "_accountId": "act_384730851257635", "spend": 50.50, "impressions": 22910, "clicks": 188, "ctr": 0.0082, "cpm": 2.204, "reach": 19400, "videoViews": 5600, "hookRate": 0.244, "purchases": 2, "purchaseValue": 180.00, "roas": 3.56, "costPerResult": 25.25 } ], "pagination": { "offset": 0, "limit": 10, "total": 5, "hasMore": false }, "metadata": { "platform": "facebook", "source": "bigquery" } } ``` **Account validation:** The endpoint validates that the requested accountIds belong to your API key. If some accounts are invalid, valid ones are queried and a warning is returned for the skipped ones. **Diagnostics (metadata.warnings):** When data is empty or partially unavailable, the response includes `metadata.warnings` — an array of human-readable strings explaining why. Examples: - `"Reporting pipeline not configured for account act_123. Connect the account in AdManage settings to enable performance data."` - `"No Facebook access token found. Ensure a token is connected in AdManage settings."` - `"The following account IDs were skipped (not found for this API key): act_999"` - `"No data found in reporting pipeline for the requested date range."` - `"No Google Ads access token found. Connect Google Ads in AdManage settings."` - `"No Google Ads data found for the requested date range. Verify the account is connected and has spend in this window."` **Platforms supported by /v1/reports/query:** Meta/Facebook, TikTok, Pinterest, and Google Ads. Google Ads reporting is returned from the Google Ads API fallback and includes campaign/ad group level performance where available. **Google Ads account IDs:** Unlike Meta (`act_...`), Google Ads account IDs are plain 10-digit customer IDs with no prefix and no dashes (e.g. `1234567890`, not `123-456-7890`). They are not included automatically — you must add them to `accountIds` alongside your Meta/TikTok IDs, otherwise Google spend will not appear in the response. Use GET /v1/adaccounts to look up your Google account IDs (they are returned with `"type": "google_ads"`). Example mixing Meta + Google in one query: ```bash curl -sS "https://api.admanage.ai/v1/reports/query?accountIds=act_384730851257635,1234567890&startDate=2026-02-01&endDate=2026-02-20&metrics=spend,impressions,clicks" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": [], "pagination": { "offset": 0, "limit": 25, "total": 0, "hasMore": false }, "metadata": { "platform": "facebook", "source": "none", "warnings": [ "Reporting pipeline not configured for account act_123. Connect the account in AdManage settings to enable performance data.", "No Facebook access token found. Ensure a token is connected in AdManage settings." ] } } ``` **Filter operators:** EQUALS, NOT_EQUALS, HIGHER_THAN, LOWER_THAN, CONTAINS, NOT_CONTAINS, STARTS_WITH, ENDS_WITH, IN, NOT_IN, BETWEEN, NOT_BETWEEN, EMPTY, NOT_EMPTY Example: Group by campaign name: ```bash curl -sS "https://api.admanage.ai/v1/reports/query?accountIds=act_384730851257635&startDate=2026-02-01&endDate=2026-02-20&metrics=spend,impressions,clicks,purchases,roas&groupBy=campaignName&sortBy=spend&sortDirection=DESC&limit=25" \ -H "Authorization: Bearer " ``` Example: Group by ad set name: ```bash curl -sS "https://api.admanage.ai/v1/reports/query?accountIds=act_384730851257635&startDate=2026-02-01&endDate=2026-02-20&metrics=spend,impressions,ctr,roas&groupBy=adsetName&sortBy=spend&sortDirection=DESC&limit=25" \ -H "Authorization: Bearer " ``` ### GET /v1/reports/meta/reach-composition Dedicated Meta reach-composition endpoint. Mirrors the core calculations behind the AdManage reach page and returns monthly reach, cumulative reach, and incremental reach (same as net-new reach) for one ad account. Query parameters: | Param | Required | Description | |-------|----------|-------------| | accountId | yes | One Meta ad account ID (e.g. "act_384730851257635") | | startDate | yes | Start date (YYYY-MM-DD) | | endDate | yes | End date (YYYY-MM-DD) | | campaignIds | no | Comma-separated campaign IDs to filter | | countries | no | Comma-separated country codes (e.g. "US,CA") | | workspaceId | no | Workspace ID for token resolution | ```bash curl -sS "https://api.admanage.ai/v1/reports/meta/reach-composition?accountId=act_384730851257635&startDate=2025-01-01&endDate=2025-03-31" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": [ { "month": "2025-01", "monthLabel": "Jan 2025", "reach": 120000, "cumulativeReach": 120000, "rawNetNewReach": 120000, "netNewReach": 120000, "incrementalReach": 120000, "previouslyReached": 0, "pctNetNew": 100, "impressions": 210000, "frequency": 1.75 }, { "month": "2025-02", "monthLabel": "Feb 2025", "reach": 90000, "cumulativeReach": 176000, "rawNetNewReach": 56000, "netNewReach": 56000, "incrementalReach": 56000, "previouslyReached": 34000, "pctNetNew": 62.22, "impressions": 171000, "frequency": 1.9 } ], "summary": { "totalCumulativeReach": 176000, "lastMonthNetNewReach": 56000, "lastMonthIncrementalReach": 56000, "avgPctNetNew": 81.11, "avgFrequency": 1.825, "trend": "down" }, "filters": { "campaigns": [ { "id": "12020001", "name": "Q1 Broad", "spend": 1425.32, "status": "ACTIVE", "isActive": true } ], "countries": [ { "code": "US", "name": "US", "spend": 1300.22 } ] }, "metadata": { "platform": "facebook", "source": "facebook_api" } } ``` Notes: - `incrementalReach` is an alias of `netNewReach`. - When campaign filters are applied, cumulative reach is rebased to the filtered window so the first active month starts at zero baseline. - If access is missing or the token is expired, the endpoint returns empty data with details in `metadata.warnings` and may include `metadata.requiresReauth=true`. ### GET /v1/reports/fields Returns all available dimensions and metrics for building report queries. Each entry includes name, label, type, format, and description. ```bash curl -sS "https://api.admanage.ai/v1/reports/fields" \ -H "Authorization: Bearer " ``` ```json { "success": true, "dimensions": [ { "name": "adId", "label": "Unique Ad", "type": "dimension" }, { "name": "adName", "label": "Ad name", "type": "dimension" }, { "name": "adsetName", "label": "Adset name", "type": "dimension" }, { "name": "campaignName", "label": "Campaign name", "type": "dimension" }, { "name": "landingPage", "label": "Landing page", "type": "dimension" }, { "name": "assetType", "label": "Ad type", "type": "dimension" }, { "name": "creative", "label": "Creative", "type": "dimension" }, { "name": "videoAsset", "label": "Video", "type": "dimension" }, { "name": "imageAsset", "label": "Image", "type": "dimension" }, { "name": "body", "label": "Copy", "type": "dimension" }, { "name": "title", "label": "Headline", "type": "dimension" }, { "name": "callToActionType", "label": "Call to action", "type": "dimension" }, { "name": "adStatus", "label": "Ad status", "type": "dimension" }, { "name": "objective", "label": "Campaign Objective", "type": "dimension" } ], "metrics": [ { "name": "spend", "label": "Amount Spent", "type": "metric", "format": "MONEY" }, { "name": "impressions", "label": "Impressions", "type": "metric", "format": "NUMBER" }, { "name": "clicks", "label": "Clicks", "type": "metric", "format": "NUMBER" }, { "name": "reach", "label": "Reach", "type": "metric", "format": "NUMBER" }, { "name": "videoViews", "label": "3 second video views", "type": "metric", "format": "NUMBER" }, { "name": "thruPlays", "label": "Thruplay", "type": "metric", "format": "NUMBER" }, { "name": "purchases", "label": "Purchases", "type": "metric", "format": "NUMBER" }, { "name": "purchaseValue", "label": "Purchase Value", "type": "metric", "format": "MONEY" }, { "name": "leads", "label": "Leads", "type": "metric", "format": "NUMBER" }, { "name": "results", "label": "Results", "type": "metric", "format": "NUMBER" }, { "name": "cpm", "label": "CPM", "type": "calculated", "format": "MONEY" }, { "name": "ctr", "label": "CTR", "type": "calculated", "format": "PERCENTAGE" }, { "name": "clicksCost", "label": "CPC", "type": "calculated", "format": "MONEY" }, { "name": "frequency", "label": "Frequency", "type": "calculated", "format": "FLOAT" }, { "name": "hookRate", "label": "Hook Rate", "type": "calculated", "format": "PERCENTAGE" }, { "name": "vtr", "label": "VTR", "type": "calculated", "format": "PERCENTAGE" }, { "name": "roas", "label": "ROAS", "type": "calculated", "format": "FLOAT" }, { "name": "purchaseCostPer", "label": "Cost Per Purchase", "type": "calculated", "format": "MONEY" }, { "name": "costPerResult", "label": "Cost Per Result", "type": "calculated", "format": "MONEY" } ] } ``` ## Daily Ad Spend Get daily ad spend per account across all connected platforms. Useful for balance management and budget monitoring. Supports Facebook/Meta (via BigQuery + Graph API fallback), TikTok, Pinterest, Snapchat, and Google Ads. ### GET /v1/spend/daily Returns daily spend broken down by ad account. Query parameters: | Param | Required | Description | |-------|----------|-------------| | startDate | yes | Start date (YYYY-MM-DD) | | endDate | yes | End date (YYYY-MM-DD) | | accountIds | no | Comma-separated ad account IDs to filter (defaults to all accounts) | | workspaceId | no | Filter to a specific workspace | | platform | no | Filter by platform: "facebook", "tiktok", "pinterest", "snapchat", "google_ads" | Date range is capped at 90 days per request. ```bash curl -sS "https://api.admanage.ai/v1/spend/daily?startDate=2026-03-01&endDate=2026-03-09" \ -H "Authorization: Bearer " ``` Example with filters: ```bash curl -sS "https://api.admanage.ai/v1/spend/daily?startDate=2026-03-01&endDate=2026-03-09&accountIds=act_384730851257635&platform=facebook" \ -H "Authorization: Bearer " ``` Response: ```json { "success": true, "data": [ { "date": "2026-03-01", "accountId": "act_384730851257635", "accountName": "Admanage Limited", "platform": "facebook", "currency": "USD", "spend": 150.42 }, { "date": "2026-03-01", "accountId": "7486153503963054097", "accountName": "TikTok Main Account", "platform": "tiktok", "currency": "USD", "spend": 75.00 } ], "metadata": { "startDate": "2026-03-01", "endDate": "2026-03-09", "accountCount": 2, "totalSpend": 367.60, "platforms": ["facebook", "tiktok"], "lastSyncedAt": "2026-03-09T10:11:48.000Z" } } ``` Data freshness: - `metadata.lastSyncedAt` is when AdManage's warehouse data (Meta) was last synced from the platform (ISO 8601). Null when every returned row was fetched live from a platform API. - Meta figures reflect the account state at `lastSyncedAt`: a day that was still in progress at that time (or synced before Meta finished settling it — up to 48h after day-end UTC) may still increase on a later sync. - For automated reporting on previous-day Meta spend, check that `lastSyncedAt` is comfortably after the day ended (ideally 48h) before publishing. If a platform fails (e.g. token expired), partial results are returned with an errors array: ```json { "success": true, "data": [...], "metadata": {...}, "errors": [ { "platform": "tiktok", "message": "TikTok not connected" } ] } ``` **Diagnostics (warnings):** When no accounts match, the response includes a top-level `warnings` array explaining why: ```json { "success": true, "data": [], "metadata": { "startDate": "2026-03-01", "endDate": "2026-03-09", "accountCount": 0, "totalSpend": 0, "platforms": [] }, "warnings": [ "None of the requested account IDs (act_999) were found for this API key. Verify the account IDs are correct and connected in AdManage settings." ] } ``` ## Comments Retrieve and manage ad comments. Comments are collected in real-time from Facebook/Meta via webhook subscriptions, with AI-powered sentiment analysis (1-100 scale). Sentiment scale: 1-33 = negative, 34-66 = neutral, 67-100 = positive. ### GET /v1/comments List comments with filtering and pagination. Query parameters: | Param | Required | Description | |-------|----------|-------------| | page | no | Page number (default 1) | | limit | no | Results per page, max 100 (default 25) | | accountId | no | Filter by ad account ID, e.g. act_123 (also accepts adAccountId) | | adId | no | Filter by specific ad ID | | sentiment | no | Filter: "positive" (67-100), "neutral" (34-66), "negative" (1-33) | | hidden | no | Filter by hidden status: "true" or "false" | | startDate | no | Start date (YYYY-MM-DD) | | endDate | no | End date (YYYY-MM-DD) | | search | no | Search in comment text, author name, or ad name (case-insensitive) | | sortBy | no | Sort field: "commentDate", "likes", "sentiment", "lastUpdated" (default: commentDate) | | sortDirection | no | "ASC" or "DESC" (default: DESC) | ```bash curl -sS "https://api.admanage.ai/v1/comments?page=1&limit=25&accountId=act_123&sentiment=negative" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": [ { "id": 4554179, "commentId": "1542661021111818_1245574530890886", "text": "Great product, love it!", "author": "John Doe", "authorId": "26271573105814472", "date": "2026-03-10T14:30:00.000Z", "likes": 5, "replyCount": 2, "sentiment": 85, "sentimentLabel": "positive", "hidden": false, "adId": "120248289622780456", "adName": "Spring Sale - UGC", "accountId": "act_123456789", "permalink": "https://www.facebook.com/...", "companyReply": null, "companyReplyTime": null, "reply": null, "spend": null, "impressions": null, "analysis": null } ], "pagination": { "page": 1, "limit": 25, "total": 39562, "totalPages": 1583 } } ``` ### GET /v1/comments/analytics Get aggregated comment analytics: sentiment distribution, top ads by comment count, and daily volume over time. Query parameters: | Param | Required | Description | |-------|----------|-------------| | accountId | no | Filter by ad account ID, e.g. act_123 (also accepts adAccountId) | | startDate | no | Start date (YYYY-MM-DD) | | endDate | no | End date (YYYY-MM-DD) | If no date range is provided, volumeOverTime defaults to the last 30 days. ```bash curl -sS "https://api.admanage.ai/v1/comments/analytics?accountId=act_123&startDate=2026-03-01&endDate=2026-03-31" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": { "summary": { "totalComments": 24347, "avgSentiment": 42.2, "analyzedComments": 24116, "hiddenComments": 10571, "commentsWithReplies": 749 }, "sentimentDistribution": { "positive": { "count": 5087, "percentage": 21 }, "neutral": { "count": 6800, "percentage": 28 }, "negative": { "count": 12229, "percentage": 51 } }, "topAds": [ { "adId": "120248289622780456", "adName": "Spring Sale - UGC", "commentCount": 85, "avgSentiment": 72.5, "totalLikes": 230 } ], "volumeOverTime": [ { "date": "2026-03-01T00:00:00.000Z", "count": 701 }, { "date": "2026-03-02T00:00:00.000Z", "count": 626 } ] } } ``` ## Launch Drafts Save, iterate, and launch ad drafts via the API. - POST /v1/drafts Body: { title, businessId (required), workspaceId, status, state } ```bash curl -sS -X POST "https://api.admanage.ai/v1/drafts" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"title":"My Draft","businessId":"act_123","state":{"globalDefaults":{"title":"Spring Sale"},"rows":[]}}' ``` Response (201): ```json { "success": true, "draftId": 42, "draftUrl": "https://admanage.ai/ingestDraft?draftId=42&businessId=act_123", "viewDraftPath": "/ingestDraft?draftId=42&businessId=act_123", "data": { "id": 42, "title": "My Draft", "businessId": "act_123", "workspaceId": null, "status": "draft", "user": "user@acme.com", "company": "acme", "createdAt": "2026-02-19T10:00:00.000Z", "state": { "globalDefaults": { "title": "Spring Sale" }, "rows": [] } } } ``` Simplified draft body: `POST /v1/drafts` also accepts `{ title, ads }` with the same ad shape as `POST /v1/launch`. For Meta Instagram post boosts, pass `instagramPostUrl` or `instagramPostUrls`; AdManage resolves the organic post and creates one draft row per URL. ```bash curl -sS -X POST "https://api.admanage.ai/v1/drafts" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "title": "IG post boost draft", "ads": [ { "adName": "Boost IG reel draft", "adAccountId": "act_384730851257635", "workspaceId": "workspace_abc", "instagramPostUrl": "https://www.instagram.com/reel/BoostMe_123/", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "page": "470703006115773", "insta": "17841471826052348", "adSets": [ { "value": "120248289622780456", "label": "US Broad 25-44" } ] } ] }' ``` - GET /v1/drafts Query: page, limit, businessId, workspaceId, search ```bash curl -sS "https://api.admanage.ai/v1/drafts?page=1&limit=25&businessId=act_123" \ -H "Authorization: Bearer " ``` ```json { "data": [ { "id": 42, "title": "My Draft", "businessId": "act_123", "workspaceId": null, "status": "draft", "user": "user@acme.com", "company": "acme", "createdAt": "2026-02-19T10:00:00.000Z" } ], "pagination": { "page": 1, "limit": 25, "total": 1, "totalPages": 1 } } ``` - GET /v1/drafts/:id ```bash curl -sS "https://api.admanage.ai/v1/drafts/42" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": { "id": 42, "title": "My Draft", "businessId": "act_123", "status": "draft", "state": { "globalDefaults": { "title": "Spring Sale" }, "rows": [] }, "createdAt": "2026-02-19T10:00:00.000Z" } } ``` - PATCH /v1/drafts/:id Body: { title?, businessId?, workspaceId?, status?, state? } ```bash curl -sS -X PATCH "https://api.admanage.ai/v1/drafts/42" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"title":"Updated Draft","state":{"globalDefaults":{"title":"Summer Sale"},"rows":[{"id":"row-1"}]}}' ``` ```json { "success": true, "data": { "id": 42, "title": "Updated Draft", "status": "draft", "state": { "globalDefaults": { "title": "Summer Sale" }, "rows": [{ "id": "row-1" }] } } } ``` - DELETE /v1/drafts/:id ```bash curl -sS -X DELETE "https://api.admanage.ai/v1/drafts/42" \ -H "Authorization: Bearer " ``` ```json { "success": true, "message": "Draft deleted" } ``` - POST /v1/drafts/:id/launch ```bash curl -sS -X POST "https://api.admanage.ai/v1/drafts/42/launch" \ -H "Authorization: Bearer " ``` Response (202): ```json { "success": true, "message": "Ad launch initiated successfully", "adBatchSlug": "a1b2c3d4", "adBatchId": 9913, "isAsync": true } ``` ## Media Library Browse, search, and filter creative assets in your media library. - GET /v1/library/assets Query: search, filterType (all|image|video|gif), sortBy (dateCreated|dateModified|name|size), sortOrder (asc|desc), boardId, creativeStatus (raw|in_progress|approved|archived), launchStatus (Launched|Not Launched), launchChannels (comma-sep: meta,tiktok,snapchat,pinterest,axon), tags (comma-sep), dimension (1080x1920 or 9:16), uploader (email), limit (max 100), cursor ```bash curl -sS "https://api.admanage.ai/v1/library/assets?limit=10&filterType=video&sortBy=dateCreated&sortOrder=desc" \ -H "Authorization: Bearer " ``` ```json { "assets": [ { "id": 12345, "adid": 67890, "name": "Spring-UGC.mp4", "url": "https://media.admanage.ai/acme/Spring-UGC.mp4", "thumbnail": "https://media.admanage.ai/acme/thumb-Spring-UGC.jpg", "mimeType": "video/mp4", "size": 15728640, "dimension": "1080x1920", "type": "video", "dateAdded": "2026-02-18T08:25:12.000Z", "lastUpdated": "2026-02-18T10:00:00.000Z", "uploaderStatus": "approved", "status": "Launched", "launchChannels": [ { "platform": "meta", "adIds": ["120012345678901234"] } ], "tags": [{ "id": 1, "name": "UGC" }], "boardIds": [10, 22] } ], "nextCursor": "12344", "hasMore": true, "total": 847 } ``` - GET /v1/library/assets/:id ```bash curl -sS "https://api.admanage.ai/v1/library/assets/12345" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": { "id": 12345, "name": "Spring-UGC.mp4", "url": "https://media.admanage.ai/acme/Spring-UGC.mp4", "type": "video", "transcript": "Hey guys, check out this amazing product...", "smartSummary": "UGC testimonial video featuring product demo", "smartTags": ["ugc", "testimonial", "product-demo"], "launchChannels": [ { "platform": "meta", "adIds": ["120012345678901234"] } ] } } ``` - GET /v1/library/boards ```bash curl -sS "https://api.admanage.ai/v1/library/boards" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": [ { "id": 10, "name": "Q1 Creatives", "visibility": "team", "assetCount": 42, "children": [ { "id": 11, "name": "UGC", "assetCount": 18, "children": [] } ] } ] } ``` - GET /v1/library/boards/:id/assets Same query params and response shape as GET /v1/library/assets, scoped to a specific board. ```bash curl -sS "https://api.admanage.ai/v1/library/boards/10/assets?limit=25" \ -H "Authorization: Bearer " ``` - GET /v1/library/tags ```bash curl -sS "https://api.admanage.ai/v1/library/tags" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": [ { "id": 1, "name": "UGC", "company": "acme" }, { "id": 2, "name": "Product Demo", "company": "acme" } ] } ``` ## Manage (Create) Create new Meta campaigns and ad sets from scratch. These endpoints now mirror the richer /manage create flow, including CBO budgets, promoted objects, app-promotion bindings, website lead setups, value rules, schedules, and advanced destination settings. - POST /v1/manage/create-campaign Create a new Meta campaign. Body: - Required: { accountId, name, objective } - Common: { status? ("ACTIVE"|"PAUSED"), buyingType? ("AUCTION"|"RESERVED"), specialAdCategories? ([] | ["EMPLOYMENT"|"HOUSING"|"FINANCIAL_PRODUCTS_SERVICES"|"CREDIT"|"ISSUES_ELECTIONS_POLITICS"]), workspaceId? } - Campaign-budget optimization (CBO): { dailyBudget? | lifetimeBudget? } in account currency dollars - Advanced /manage parity fields: { campaignSpendCap?, campaignBudgetType? ("daily"|"lifetime"), campaignBudgetOptimization?, isAdvantagePlusCampaign?, bidStrategy?, campaignBidAmount?, isSkadnetworkAttribution?, promotedObject? } Objectives: - OUTCOME_TRAFFIC - OUTCOME_ENGAGEMENT - OUTCOME_LEADS - OUTCOME_AWARENESS - OUTCOME_SALES - OUTCOME_APP_PROMOTION Campaign promotedObject: - Sales catalog ads: { "product_catalog_id": "..." } - App promotion / SKAdNetwork: { "application_id": "...", "object_store_url": "..." } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/create-campaign" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "accountId":"act_123", "name":"Q2 Prospecting", "objective":"OUTCOME_SALES", "status":"PAUSED", "dailyBudget":100, "bidStrategy":"COST_CAP", "campaignBidAmount":35, "promotedObject":{"product_catalog_id":"9988776655"} }' ``` ```json { "success": true, "campaignId": "120248400000000001", "name": "Q2 Prospecting", "objective": "OUTCOME_SALES", "status": "PAUSED", "accountId": "act_123" } ``` More sales campaign examples: Standard website sales campaign: ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/create-campaign" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "accountId":"act_123", "name":"Website Sales", "objective":"OUTCOME_SALES", "status":"PAUSED", "dailyBudget":150, "bidStrategy":"LOWEST_COST_WITHOUT_CAP" }' ``` Advantage+ catalog sales campaign: ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/create-campaign" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "accountId":"act_123", "name":"Catalog Sales", "objective":"OUTCOME_SALES", "status":"PAUSED", "dailyBudget":300, "campaignBudgetOptimization":true, "isAdvantagePlusCampaign":true, "promotedObject":{"product_catalog_id":"9988776655"} }' ``` - POST /v1/manage/create-adset Create a new Meta ad set inside an existing campaign. Body: - Required: { accountId, campaignId (or campaign_id), name } - Common: { status?, optimizationGoal? (or optimization_goal), billingEvent? (or billing_event), bidStrategy?, bidAmount?, dailyBudget? | lifetimeBudget?, startTime?, endTime?, targeting?, promotedObject?, destinationType?, workspaceId? } - Advanced /manage parity fields: { attributionSpec?, dsaBeneficiary?, dsaPayor?, dailySpendCap?, lifetimeSpendCap?, valueRuleSetId?, valueRulesApplied?, placementSoftOptOut?, pacingType?, adsetSchedule?, budgetSchedules? } If optimizationGoal is omitted, the API infers the default from the campaign objective: - OUTCOME_TRAFFIC → LANDING_PAGE_VIEWS - OUTCOME_ENGAGEMENT / MESSAGES → CONVERSATIONS - POST_ENGAGEMENT → POST_ENGAGEMENT - OUTCOME_LEADS → LEAD_GENERATION - OUTCOME_AWARENESS → REACH - OUTCOME_SALES → OFFSITE_CONVERSIONS - OUTCOME_APP_PROMOTION → APP_INSTALLS Common destination types: - WEBSITE - APP - MESSENGER - WHATSAPP - INSTAGRAM_DIRECT - ON_AD - WEBSITE_AND_PHONE_CALL Promoted object examples: - Website conversions / sales: { "pixel_id": "123", "custom_event_type": "PURCHASE" } - Website leads with datasets: { "offline_conversion_data_set_id": "123", "custom_event_type": "LEAD" } - Instant-form leads / awareness / engagement: { "page_id": "123" } - App promotion: { "application_id": "123", "object_store_url": "https://apps.apple.com/app/id123" } - Sales messaging destinations: { "page_id": "123" } Sales-focused ad set examples: - Website purchases: { "optimizationGoal":"OFFSITE_CONVERSIONS", "destinationType":"WEBSITE", "promotedObject":{"pixel_id":"123","custom_event_type":"PURCHASE"} } - Website value / ROAS: { "optimizationGoal":"VALUE", "destinationType":"WEBSITE", "promotedObject":{"pixel_id":"123","custom_event_type":"PURCHASE"} } - Website and calls: { "optimizationGoal":"OFFSITE_CONVERSIONS", "destinationType":"WEBSITE_AND_PHONE_CALL", "promotedObject":{"pixel_id":"123","custom_event_type":"PURCHASE"} } - Messaging destinations: { "optimizationGoal":"OFFSITE_CONVERSIONS", "destinationType":"MESSAGING_INSTAGRAM_DIRECT_MESSENGER_WHATSAPP", "promotedObject":{"page_id":"123"} } - Calls only: { "optimizationGoal":"OFFSITE_CONVERSIONS", "destinationType":"PHONE_CALL" } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/create-adset" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "accountId":"act_123", "campaignId":"120248400000000001", "name":"US Broad 25-54", "optimizationGoal":"OFFSITE_CONVERSIONS", "dailyBudget":50, "bidStrategy":"COST_CAP", "bidAmount":20, "targeting":{ "geo_locations":{"countries":["US"]}, "age_min":25, "age_max":54, "genders":[1,2] }, "promotedObject":{"pixel_id":"123456","custom_event_type":"PURCHASE"}, "attributionSpec":[{"event_type":"CLICK_THROUGH","window_days":7}], "valueRuleSetId":"120200000000000001", "valueRulesApplied":true }' ``` ```json { "success": true, "adSetId": "120248400000000002", "name": "US Broad 25-54", "campaignId": "120248400000000001", "status": "PAUSED", "accountId": "act_123" } ``` ## Manage (Duplicate) Duplicate campaigns, ad sets, and ads on Facebook. - POST /v1/manage/duplicate-adset Duplicate a Facebook ad set (1-10 copies). Uses smartCopy (sync first, async batch fallback for large ad sets). Body: { adSetId (or adsetId), accountId, copyCount (1-10), initialStatus ("ACTIVE"|"PAUSED"), targetCampaignId?, newName?, deepCopy? (default false), bidAmount? (account-currency dollars), bidStrategy? ("LOWEST_COST_WITHOUT_CAP"|"LOWEST_COST_WITH_BID_CAP"|"COST_CAP"|"TARGET_COST"), workspaceId? } For capped CBO destinations, pass bidAmount; the campaign strategy is inherited and AdManage sends the required ad-set bid amount in Meta minor units with the copy request. ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/duplicate-adset" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"adsetId":"120248289622780456","accountId":"act_123","copyCount":2,"initialStatus":"PAUSED","deepCopy":true}' ``` ```json { "success": true, "originalAdSetId": "120248289622780456", "results": [ { "copyNumber": 1, "success": true, "newAdSetId": "120248289622780457" }, { "copyNumber": 2, "success": true, "newAdSetId": "120248289622780458" } ], "successCount": 2, "failCount": 0 } ``` - POST /v1/manage/duplicate-campaign Duplicate a Meta/Facebook or Taboola campaign (1-10 copies). For Taboola, set platform:"taboola"; includeItems defaults true. Body: { campaignId, accountId, copyCount (1-10), platform? ("facebook"|"meta"|"taboola"), initialStatus? ("ACTIVE"|"PAUSED"), newName?, deepCopy?, copyDepth?, includeItems?, workspaceId? } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/duplicate-campaign" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"campaignId":"120247699100220456","accountId":"act_123","copyCount":1,"initialStatus":"PAUSED"}' ``` ```json { "success": true, "originalCampaignId": "120247699100220456", "results": [ { "copyNumber": 1, "success": true, "newCampaignId": "120247699100220457" } ], "successCount": 1, "failCount": 0 } ``` Taboola example: ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/duplicate-campaign" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"platform":"taboola","campaignId":"campaign-123","accountId":"taboolaaccount-cedadmanageai","copyCount":1,"newName":"Taboola Campaign Copy","includeItems":true,"workspaceId":"workspace_abc"}' ``` - POST /v1/manage/axon/duplicate-campaign Duplicate an Axon/AppLovin campaign through Axon's public manage API. Body: { businessId, sourceCampaignId, newCampaignName, status ("LIVE"|"PAUSED")?, startDate? ("YYYY-MM-DD" or "YYYY-MM-DDTHH:MM:SS"), workspaceId? } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/axon/duplicate-campaign" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"businessId":"1159321785","sourceCampaignId":"1786048","newCampaignName":"Campaign copy via API","status":"PAUSED","startDate":"2026-04-08T19:39:00","workspaceId":"workspace_abc"}' ``` ```json { "success": true, "campaignId": "1919062", "campaign": { "id": "1919062", "name": "Campaign copy via API", "status": "PAUSED", "type": "APP" }, "warnings": [ { "code": "AXON_APP_MIN_BUDGET_APPLIED", "message": "Axon APP campaigns require a minimum create budget of 500. Increased the create budget during duplication." } ] } ``` Notes: - This uses Axon's public `campaign/create` API and then applies a follow-up `campaign/update` when you request `PAUSED`. - APP campaigns preserve source tracking fields such as `tracking`, `platform`, `package_name`, and composite banner settings. - If Axon rejects the source APP budget during create, the API raises it to Axon's minimum create budget and returns a warning. - POST /v1/manage/duplicate-ad Duplicate a Facebook ad with optional creative modifications (primary text, headlines, URL, URL tags). Recreates creatives when necessary to remove deprecated 191x100 crop metadata or convert a standard image/video creative for an empty Dynamic Creative ad set. Body: { adId, accountId, targetAdSetId, copyCount (1-10), initialStatus ("ACTIVE"|"PAUSED"), copyValues: { primaryText1-5?, headline1-5?, url?, urlTags?, adName? }, workspaceId? } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/duplicate-ad" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"adId":"120012345678901234","accountId":"act_123","targetAdSetId":"120248289622780456","copyCount":1,"initialStatus":"PAUSED","copyValues":{"primaryText1":"New headline","adName":"My Ad Copy"}}' ``` ```json { "success": true, "originalAdId": "120012345678901234", "results": [ { "copyNumber": 1, "success": true, "newAdId": "120012345678901235", "method": "copies" } ], "successCount": 1, "failCount": 0 } ``` Notes: - deepCopy (default true): When true, copies all child objects (ads in ad sets, ad sets + ads in campaigns). Set to false to copy only the container. - copyCount 1-10: Number of duplicates to create in one call. ## Manage (Delete + Edit + Status) ### POST /v1/manage/delete Delete Facebook or Pinterest campaigns, ad sets, or ads (up to 100 at once). Facebook: soft-delete (status DELETED). Pinterest: archived. Body: { entityIds (string[]), entityType ("campaigns"|"adsets"|"ads"), businessId, platform? ("facebook"|"pinterest"), workspaceId? } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/delete" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"entityIds":["120249137908810789","120249137908810790"],"entityType":"ads","businessId":"act_384730851257635"}' ``` ```json { "success": true, "results": [ { "id": "120249137908810789", "success": true }, { "id": "120249137908810790", "success": true } ], "successCount": 2, "failCount": 0 } ``` ### POST /v1/manage/update-status — Pause, Resume, or End ads / ad sets / campaigns One endpoint for three things: • PAUSE (stop immediately) — newStatus: "PAUSED" (Meta) or "DISABLE" (TikTok), no endTime. • RESUME (re-activate) — newStatus: "ACTIVE" (Meta) or "ENABLE" (TikTok), no endTime. • END on a schedule (Meta) — newStatus: "ACTIVE" + endTime (ISO 8601). Delivery keeps running until endTime, then stops. • EXTEND / CHANGE end date — call again with a new endTime; it overwrites the previous one. Works on campaigns, ad sets, and ads. Platform auto-detected from businessId (act_ = Meta, numeric = TikTok). The entity does NOT need to be synced to AdManage — the ID is passed straight through to the platform API. Body: { entityId, entityType ("campaigns"|"adsets"|"ads"), newStatus ("ACTIVE"|"PAUSED" for Meta, "ENABLE"|"DISABLE" for TikTok), businessId, endTime? (ISO 8601, Meta only — schedule when delivery stops), workspaceId? } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/update-status" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"entityId":"120249137908810789","entityType":"adsets","newStatus":"ACTIVE","businessId":"act_384730851257635","endTime":"2026-04-22T23:59:59+0000"}' ``` ### POST /v1/manage/update-campaign-budget Set daily or lifetime budget for a Meta campaign. Inputs are dollars; AdManage converts to Meta cents internally and returns both amountDollars and amountCents. Body: { campaignId, businessId (act_* ad account), **either** dailyBudget **or** lifetimeBudget (number, ≥ 0, in dollars), endTime? (ISO 8601, required when using lifetimeBudget), workspaceId? } Note: Meta does not allow switching from daily to lifetime budget on an existing entity. Lifetime budget must be set at creation time. ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/update-campaign-budget" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"campaignId":"120247699100220456","businessId":"act_384730851257635","dailyBudget":150}' ``` ### POST /v1/manage/update-adset-budget Set daily or lifetime budget for a Meta ad set. Inputs are dollars; AdManage converts to Meta cents internally and returns both amountDollars and amountCents. Body: { adsetId, businessId (act_* ad account), **either** dailyBudget **or** lifetimeBudget (number, ≥ 0, in dollars), endTime? (ISO 8601, required when using lifetimeBudget), workspaceId? } Note: Meta does not allow switching from daily to lifetime budget on an existing ad set. Lifetime budget must be set at creation time. ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/update-adset-budget" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"adsetId":"120249483901820456","businessId":"act_384730851257635","dailyBudget":25}' ``` ### POST /v1/manage/update-campaign-bidding Update Meta bidding for a campaign. This only applies to AUCTION campaigns using campaign budget optimization (CBO). Body: { campaignId, businessId (act_* ad account), bidStrategy? ("LOWEST_COST_WITHOUT_CAP"|"LOWEST_COST_WITH_BID_CAP"|"COST_CAP"|"TARGET_COST"), bidAmount? (number, ≥ 0, in dollars), workspaceId? } Important Meta behavior: - Campaign bid_strategy applies at the CBO campaign level. - For capped campaign strategies, Meta stores the cap amount on each child ad set as `bid_amount`. - When switching a CBO campaign from autobid to a capped campaign strategy, Meta requires an `adset_bid_amounts` map of every non-deleted child ad set ID to its bid amount. - AdManage now sends that `adset_bid_amounts` map in the campaign update request instead of patching child ad sets directly. ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/update-campaign-bidding" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"campaignId":"120247699100220456","businessId":"act_384730851257635","bidStrategy":"LOWEST_COST_WITH_BID_CAP","bidAmount":35}' ``` ### POST /v1/manage/update-adset-bidding Update Meta bidding for an ad set. Body: { adsetId, businessId (act_* ad account), bidStrategy? ("LOWEST_COST_WITHOUT_CAP"|"LOWEST_COST_WITH_BID_CAP"|"COST_CAP"|"TARGET_COST"), bidAmount? (number, ≥ 0, in dollars), workspaceId? } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/update-adset-bidding" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"adsetId":"120249483901820456","businessId":"act_384730851257635","bidStrategy":"COST_CAP","bidAmount":12.5}' ``` ### POST /v1/manage/update-name Rename a Meta campaign, ad set, or ad. Body: { entityId, entityType ("campaigns"|"adsets"|"ads"), businessId (act_* ad account), name, workspaceId? } Aliases: campaignId, adsetId/adSetId, and adId may be used instead of entityId. ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/update-name" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"entityType":"adsets","adsetId":"120249483901820456","businessId":"act_384730851257635","name":"Prospecting - US - Broad"}' ``` ### POST /v1/manage/disable-app-events Disable Meta App events tracking on an existing ad. This removes `application` tracking specs from the ad while preserving website pixel and offline dataset tracking specs. Body: { adId, businessId (act_* ad account), workspaceId? } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/disable-app-events" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"adId":"120249137908810789","businessId":"act_384730851257635"}' ``` ### POST /v1/manage/update-adset-spending-limits Set or clear CBO ad set spending limits (daily minimum spend target and daily maximum spend cap) for an ad set inside a campaign budget optimization (CBO) campaign. Inputs are dollars; AdManage converts to Meta cents internally and sends `daily_min_spend_target` / `daily_spend_cap`. The response echoes both dollars and cents for each limit. Body: { adsetId, businessId (act_* ad account), dailyMinSpend? (number, ≥ 0, in dollars), dailySpendCap? (number, ≥ 0, in dollars), clearDailyMin? (boolean), clearDailyMax? (boolean), workspaceId? } Rules: - Provide at least one of dailyMinSpend, dailySpendCap, clearDailyMin, or clearDailyMax. - Do not send a value and its clear flag for the same field (e.g. dailyMinSpend + clearDailyMin). - When both are set, dailyMinSpend cannot exceed dailySpendCap. - clearDailyMin / clearDailyMax send 0 to Meta to remove the limit. ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/update-adset-spending-limits" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"adsetId":"120249483901820456","businessId":"act_384730851257635","dailyMinSpend":100,"dailySpendCap":500}' ``` ### POST /v1/manage/edit-ads Batch edit existing Facebook ads — change name, primary text, headlines, descriptions, URL, CTA, UTM tags, creative enhancements. Body: { accountId, ads: [{ adId, copyValues: { adName?, primaryText1?, headline1?, description1?, url?, urlTags?, cta?, creativeEnhancements? ("on"|"off") } }] } ```bash curl -sS -X POST "https://api.admanage.ai/v1/manage/edit-ads" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"accountId":"act_123","ads":[{"adId":"120249137908810789","copyValues":{"primaryText1":"Updated text","headline1":"New headline"}}]}' ``` ### GET /v1/manage/lead-forms List active lead forms for a Facebook Page. Required when launching into lead gen ad sets. The API resolves the Page access token from the stored Facebook user token before reading `/{pageId}/leadgen_forms`. Query: pageId (required), workspaceId? ```bash curl -sS "https://api.admanage.ai/v1/manage/lead-forms?pageId=470703006115773" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": [ { "id": "456789123", "name": "Contact Us Form", "status": "ACTIVE", "created_time": "2026-02-18T08:25:12+0000" } ] } ``` ### POST /v1/manage/refresh-adsets Fetch/refresh ad sets from the Facebook Graph API. Supports caching and cooldown. Body: { businessId (required, act_*), type? ("all"|"active"|"paused"), hardRefresh?, forceRefresh?, workspaceId? } ### POST /v1/manage/duplicate-adset-advanced Duplicate an ad set with optional targeting updates (locations, custom audiences) and ad duplication. Body: { adsetId, accountId, newAdSetName?, duplicateAds? (boolean), duplicateAdsStatus?, singleAdId?, locationTargeting?, customAudiencesInclude?, customAudiencesExclude?, workspaceId? } ## Manage (Library) ### POST /v1/library/assets/{id}/update Update a media asset's metadata. Body: { name?, uploaderStatus? ("raw"|"in_progress"|"approved"|"archived"), rating? (1-5), smartTags? (string[]) } ```bash curl -sS -X POST "https://api.admanage.ai/v1/library/assets/12345/update" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"uploaderStatus":"approved","rating":5,"smartTags":["hero","q1"]}' ``` ### POST /v1/library/boards Create a new board (folder) in the creative library. Body: { name (required), description?, parentId? (number, for nesting), visibility? ("team"|"private") } ### POST /v1/library/boards/{id}/assets Add an asset to a board. Body: { adId (number, asset ID) } ### DELETE /v1/library/boards/{id}/assets Remove an asset from a board (unlinks only, doesn't delete the asset). Query: adId (required) ## Comments (Reply + Hide) Respond to or moderate Facebook ad comments. Both endpoints call the Facebook Graph API on your behalf using your connected token. ### POST /v1/comments/reply Reply to a Facebook ad comment. The reply is posted as the page that owns the ad. Body: | Field | Required | Description | |-------|----------|-------------| | commentId | yes | Facebook comment ID (e.g. "1542661021111818_1245574530890886") | | message | yes | Reply text | | workspaceId | no | Workspace ID to resolve the correct Facebook token | ```bash curl -sS -X POST "https://api.admanage.ai/v1/comments/reply" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"commentId":"1542661021111818_1245574530890886","message":"Thanks for your feedback!"}' ``` ```json { "success": true, "data": { "replyId": "1542661021111818_9988776655", "commentId": "1542661021111818_1245574530890886" } } ``` ### POST /v1/comments/hide Hide or unhide a Facebook ad comment from public view. Body: | Field | Required | Description | |-------|----------|-------------| | commentId | yes | Facebook comment ID | | hide | yes | true to hide, false to unhide | | workspaceId | no | Workspace ID to resolve the correct Facebook token | ```bash curl -sS -X POST "https://api.admanage.ai/v1/comments/hide" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"commentId":"1542661021111818_1245574530890886","hide":true}' ``` ```json { "success": true, "data": { "commentId": "1542661021111818_1245574530890886", "hidden": true } } ``` ## Media (Upload Flow) ### POST /v1/media/get-upload-url Get a presigned URL for direct file upload (expires in 1 hour). Body: { fileName (required) } ```bash curl -sS -X POST "https://api.admanage.ai/v1/media/get-upload-url" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"fileName":"creative.mp4"}' ``` Upload flow: get-upload-url → upload file to returned URL → confirm-upload → (optional) generate-thumbnail ### POST /v1/media/confirm-upload Register an uploaded file in the media library after uploading via presigned URL. Body: { url (required, media.admanage.ai URL), fileName? } ### POST /v1/media/generate-thumbnail Generate a thumbnail for a video file (non-blocking). Body: { url (required, media.admanage.ai video URL) } ### POST /v1/media/subtitles Start a subtitle render job that burns styled subtitles into a video using the Create/Subtitle Maker renderer. Body: { videoUrl (required), segments?, srtText?, srtUrl?, operation?, stylePreset?, positionPreset?, fontFamily?, fontSize?, color?, outlineColor?, wordsPerCaption?, maxCaptionDuration?, params? } Backpressure: each company can have up to 3 active subtitle jobs by default, tracked through the existing Redis limiter with in-memory fallback. Extra submissions return 429 until existing jobs finish or expire from tracking. After a jobId exists, do not resubmit the same render. Poll GET /v1/media/subtitles/{jobId} or use the MCP wait_for_subtitled_video helper. ```bash curl -sS -X POST "https://api.admanage.ai/v1/media/subtitles" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"videoUrl":"https://media.admanage.ai/acme/source.mp4","segments":[{"start":0,"end":1.2,"text":"Launch faster"}],"stylePreset":"bold","positionPreset":"bottom-third"}' ``` Poll GET /v1/media/subtitles/{jobId}; when status is succeeded, call POST /v1/media/subtitles/{jobId}/publish. ### GET /v1/media/subtitles/{jobId} Poll subtitle render status. Status values: queued, running, succeeded, failed. ### POST /v1/media/subtitles/{jobId}/publish Upload a completed subtitle render result to media.admanage.ai and return a durable URL. Body: { fileName?, registerInLibrary? } ## Batch (Ad Delivery Status) ### GET /v1/adbatches/{id}/ad-delivery-statuses Get ad delivery status for all ads in a batch (Meta only). Cached for 15 minutes. Query: refresh? (true to force refresh) Every response includes launch-stage error context (`batchStatus`, `summaryStatus`, `launchError`, `launchFailedDetails`, `launchErrorMessage`, `finalMessage`) so callers can tell when a batch failed before ads were created and see the actual error message. ```bash curl -sS "https://api.admanage.ai/v1/adbatches/9911/ad-delivery-statuses" \ -H "Authorization: Bearer " ``` ```json { "success": true, "batchId": 9911, "adDeliveryStatuses": { "120249137908810789": { "effectiveStatus": "ACTIVE", "checkedAt": "2026-03-30T10:15:00.000Z" }, "120249137908810790": { "effectiveStatus": "PENDING_REVIEW", "checkedAt": "2026-03-30T10:15:00.000Z" } }, "fromCache": true, "batchStatus": "success", "summaryStatus": "success", "launchError": null, "launchFailedDetails": null, "launchErrorMessage": null, "finalMessage": "2 ads launched" } ``` ## YouTube ### POST /v1/google-ads/upload-youtube-video Upload a video URL to Google's managed YouTube ad-storage channel (no personal YouTube channel required). Uses Google Ads OAuth for accountId. Privacy is always UNLISTED. Body: { accountId (required), videoUrl (required), title (required), description?, workspaceId? } ```bash curl -sS -X POST "https://api.admanage.ai/v1/google-ads/upload-youtube-video" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"accountId":"1234567890","videoUrl":"https://media.admanage.ai/acme/creative.mp4","title":"Product Demo"}' ``` ```json { "success": true, "youtubeVideoId": "dQw4w9WgXcQ", "resourceName": "customers/1234567890/youTubeVideoUploads/42", "state": "PROCESSED" } ``` MCP equivalent: `upload_google_ads_youtube_video`. Pass the returned `youtubeVideoId` to `launch_google_ads` as `videos[].youtubeVideoId`. ### POST /v1/youtube/upload-from-url Upload a video to YouTube from a URL. Useful for API and MCP tracker workflows that need YouTube video IDs for Google Ads. Body: { videoUrl (required), title?, description?, privacy? ("public"|"unlisted"|"private"), channelId?, playlistId?, youtubeTokenId?, workspaceId?, adId?, selfDeclaredMadeForKids? } ```bash curl -sS -X POST "https://api.admanage.ai/v1/youtube/upload-from-url" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"videoUrl":"https://media.admanage.ai/acme/creative.mp4","title":"Product Demo","description":"Tracker-provided description","privacy":"unlisted"}' ``` ```json { "success": true, "videoId": "dQw4w9WgXcQ", "youtubeUrl": "https://youtube.com/watch?v=dQw4w9WgXcQ" } ``` MCP equivalent: `upload_youtube_video_from_url`. Pass the returned `videoId` to `launch_google_ads` as `videos[].youtubeVideoId`. ### GET /v1/youtube/video-status Check YouTube processing status, title, and duration for up to 50 uploaded video IDs. Query: videoIds (comma-separated, required), workspaceId? ```bash curl -sS "https://api.admanage.ai/v1/youtube/video-status?videoIds=dQw4w9WgXcQ&workspaceId=workspace_abc123" \ -H "Authorization: Bearer " ``` ```json { "videos": { "dQw4w9WgXcQ": { "processing": false, "uploadStatus": "processed", "title": "Product Demo", "durationSeconds": 31, "durationFormatted": "0:31" } } } ``` MCP equivalent: `get_youtube_video_status`. ### POST /v1/youtube/wait-for-processing Poll YouTube until uploaded videos finish processing or the wait limit is reached. Use before launching Google Ads with newly uploaded videos. Body: { videoIds (required array), workspaceId?, maxWaitMs? } — maxWaitMs is capped at 600000. ```bash curl -sS -X POST "https://api.admanage.ai/v1/youtube/wait-for-processing" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"videoIds":["dQw4w9WgXcQ"],"maxWaitMs":300000}' ``` ```json { "allReady": true, "timedOut": false, "videos": { "dQw4w9WgXcQ": { "ready": true, "uploadStatus": "processed" } } } ``` MCP equivalent: `wait_for_youtube_processing`. ## Google Ads Manage Google Ads campaigns (Performance Max, Demand Gen). All endpoints require accountId (Google Ads customer ID). ### GET /v1/google-ads/campaigns List cached campaigns and ad groups. Query: accountId (required) ```bash curl -sS "https://api.admanage.ai/v1/google-ads/campaigns?accountId=7037703309" \ -H "Authorization: Bearer " ``` ### POST /v1/google-ads/campaigns/toggle-status Toggle campaign ENABLED/PAUSED. Body: { accountId, campaignId, status ("ENABLED"|"PAUSED") } ### POST /v1/google-ads/campaigns/rename Rename a campaign. Body: { accountId, campaignId, newName } ### POST /v1/google-ads/duplicate-campaign Duplicate a campaign with all ad groups, ads, and keywords. Body: { campaignId, accountId, newName, status? } ### POST /v1/google-ads/duplicate-ad-group Duplicate an ad group with ads and keywords. Body: { campaignId, adGroupId, accountId, newName, status? } ### POST /v1/google-ads/duplicate-ad Duplicate a single ad (RSA, RDA, generic). Body: { adGroupId, adId, accountId, status? } ### POST /v1/google-ads/ad-details Get Demand Gen ad creative data (read-only despite POST). Body: { accountId, adGroupId, adId } ### POST /v1/google-ads/add-text-assets Add headlines, long headlines, descriptions to PMax asset groups. Body: { accountId, assetGroupIds (string[]), headlines?, longHeadlines?, descriptions? } ### POST /v1/google-ads/add-assets Add video/image assets to PMax asset groups or Demand Gen ads. Rate limited: 5 req/min. Body: { accountId, assetGroupIds, videos? [{ youtubeVideoId }], images? [{ base64, fieldType, aspectRatio }] } ### POST /v1/google-ads/remove-assets Remove an asset from a PMax asset group. Body: { accountId, assetId, assetGroupId } ### POST /v1/google-ads/update-assets Update text assets (immutable: removes old + creates new). Body: { accountId, editedAssets [{ assetId, text, originalText, type, assetGroupId }] } ### POST /v1/google-ads/launch Orchestrated launch — creates batch, runs all operations, updates batch. Returns 202. Rate limited: 3 req/min. Body: { accountId, accountName, assetGroupIds, assetGroupNames, headlines?, descriptions?, videos?, images?, deletions?, editedAssets? } ```json { "success": true, "batchId": 12345, "slug": "unique-slug", "isAsync": true } ``` ## Conversions (Meta CAPI) ### GET /v1/conversions/pixels List Meta pixels for an ad account. Query: businessId (required), workspaceId? ```bash curl -sS "https://api.admanage.ai/v1/conversions/pixels?businessId=act_123" \ -H "Authorization: Bearer " ``` ### POST /v1/conversions/events Send custom events to Meta Conversions API (CAPI). PII is automatically SHA-256 hashed. Body: { businessId, events [{ event_name, event_time, user_data: { em?, ph?, external_id? }, custom_data?: { value?, currency? } }], test_event_code?, workspaceId? } Rate limit: 50 req/min (up to 1000 events each = 50,000 events/min). ## Facebook Ad Rules (Native) Create, manage, and monitor native Facebook Ad Rules that run on Meta's servers. ### GET /v1/manage/rules List all rules for an account. Query: accountId (required), workspaceId? ### GET /v1/manage/rules/:id Get a specific rule. Query: workspaceId? ### POST /v1/manage/rules Create a new rule. Body: { accountId, name, actionType ("TURN_OFF"|"TURN_ON"|"NOTIFICATION"|"INCREASE_DAILY_BUDGET"|"DECREASE_DAILY_BUDGET"|"INCREASE_LIFETIME_BUDGET"|"DECREASE_LIFETIME_BUDGET"), entityType? ("AD"|"ADSET"|"CAMPAIGN"), conditions [{ field, operator, value }], scheduleType? ("DAILY"|"CONTINUOUS"), timeRange?, budgetValue?, budgetValueType? ("PERCENT"|"ABSOLUTE"), maxDailyCap?, workspaceId? } ### PATCH /v1/manage/rules/:id Update a rule. Same body fields as create (all optional). ### DELETE /v1/manage/rules/:id Delete a rule. ### GET /v1/manage/rules-history Get rule execution history. Query: accountId (required), hideNoChanges? ("true"|"false"), workspaceId? ## Automations ### List Rules - GET /v1/automations Query: page, limit, status, workspaceId, search ```bash curl -sS "https://api.admanage.ai/v1/automations?page=1&limit=25&status=active" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": [ { "id": 1, "name": "Pause low ROAS ads", "status": "active", "actionType": "pause_ad", "accountId": "act_123456789", "frequency": "daily", "scheduledDate": "2026-02-27", "scheduledTime": "09:00", "workspaceId": "workspace_abc", "createdAt": "2026-02-20T10:00:00.000Z", "updatedAt": "2026-02-25T14:30:00.000Z" } ], "pagination": { "page": 1, "limit": 25, "total": 1, "totalPages": 1 } } ``` ### Get Rule - GET /v1/automations/:id Returns the rule with its 10 most recent executions. ```bash curl -sS "https://api.admanage.ai/v1/automations/1" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": { "id": 1, "name": "Pause low ROAS ads", "status": "active", "flow": { "nodes": [ { "id": "node-trigger-1", "type": "trigger", "service": "meta-ads", "event": "Performance Threshold", "config": { "accountId": "act_123456789" }, "position": 1 }, { "id": "node-action-2", "type": "action", "service": "meta-ads", "event": "Pause Ad", "config": { "accountId": "act_123456789", "targetIds": "{{node-trigger-1.qualifyingAdIds}}" }, "position": 2 } ] }, "actionType": "pause_ad", "accountId": "act_123456789", "targetId": null, "newName": null, "frequency": "daily", "scheduledDate": "2026-02-27", "scheduledTime": "09:00", "dayOfWeek": null, "dayOfMonth": null, "startDate": null, "endDate": null, "userId": "usr_01HXYZ", "userEmail": "user@acme.com", "company": "acme", "workspaceId": "workspace_abc", "createdAt": "2026-02-20T10:00:00.000Z", "updatedAt": "2026-02-25T14:30:00.000Z", "executions": [ { "id": 101, "status": "completed", "executedAt": "2026-02-26T09:00:05.000Z", "completedAt": "2026-02-26T09:00:12.000Z", "duration": 7000, "errorMessage": null } ] } } ``` ### Create Rule - POST /v1/automations Body: name (required), flow (required, object with nodes array), actionType (required), accountId (required), targetId?, newName?, frequency? ("one-time"|"daily"|"weekly"|"monthly", default "one-time"), scheduledDate?, scheduledTime?, dayOfWeek?, dayOfMonth?, startDate?, endDate?, status? (default "active"), workspaceId? Flow node shape: { id, type ("trigger"|"action"|"filter"|"delay"|"approval"), service, event, config, position }. Notification action node: service "notification", event "Send Notification", config { notificationMethod: "email"|"slack"|"both", slackChannelOverride?: { id, name }, emailRecipients?: string[], customMessage?: string }. Webhook action node: service "webhook", event "Send Webhook", config { url, method: "GET"|"POST"|"PUT"|"PATCH"|"DELETE", headers?: [{ key, value }], body?: string }. ```bash curl -sS -X POST "https://api.admanage.ai/v1/automations" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"name":"Notify on high spend","flow":{"nodes":[{"id":"node-trigger-1","type":"trigger","service":"meta-ads","event":"Performance Threshold","config":{"accountId":"act_123456789","criteria":{"conditions":[{"metric":"spend","operator":">","value":1000}],"logic":"AND","lookbackDays":1}},"position":1},{"id":"node-action-2","type":"action","service":"notification","event":"Send Notification","config":{"notificationMethod":"email","emailRecipients":["ops@example.com"],"customMessage":"Spend threshold reached"},"position":2}],"edges":[{"source":"node-trigger-1","target":"node-action-2"}]},"actionType":"notify","accountId":"act_123456789","frequency":"daily","scheduledTime":"09:00","workspaceId":"workspace_abc"}' ``` ```json { "success": true, "data": { "id": 2, "name": "Notify on high spend", "status": "active", "flow": { "nodes": [ { "id": "node-trigger-1", "type": "trigger", "service": "meta-ads", "event": "Performance Threshold", "config": { "accountId": "act_123456789" }, "position": 1 }, { "id": "node-action-2", "type": "action", "service": "notification", "event": "Send Notification", "config": { "notificationMethod": "email", "emailRecipients": ["ops@example.com"] }, "position": 2 } ] }, "actionType": "notify", "accountId": "act_123456789", "frequency": "daily", "scheduledDate": "2026-02-27", "scheduledTime": "09:00", "workspaceId": "workspace_abc", "createdAt": "2026-02-27T15:00:00.000Z", "updatedAt": "2026-02-27T15:00:00.000Z" } } ``` ### Update Rule - PATCH /v1/automations/:id Body: any combination of name, flow, actionType, accountId, targetId, newName, status, frequency, scheduledDate, scheduledTime, dayOfWeek, dayOfMonth, startDate, endDate, workspaceId. At least one field required. ```bash curl -sS -X PATCH "https://api.admanage.ai/v1/automations/2" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"status":"paused"}' ``` ```json { "success": true, "data": { "id": 2, "name": "Pause low ROAS ads", "status": "paused", "frequency": "daily", "updatedAt": "2026-02-27T16:00:00.000Z" } } ``` ### Delete Rule - DELETE /v1/automations/:id ```bash curl -sS -X DELETE "https://api.admanage.ai/v1/automations/2" \ -H "Authorization: Bearer " ``` ```json { "success": true, "message": "Rule 2 deleted" } ``` ### Execute Rule by ID - POST /v1/automations/:id/execute Runs an existing saved rule. Returns 202 Accepted with an executionId to poll. ```bash curl -sS -X POST "https://api.admanage.ai/v1/automations/1/execute" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": { "executionId": 102, "status": "running", "message": "Poll GET /v1/automations/executions/102 for status." } } ``` ### Execute Inline (no saved rule) - POST /v1/automations/execute Body: flow (required, object with nodes array), actionType (required), accountId (required), name?, targetId?, newName?, dryRun? (boolean), workspaceId? Returns 202 Accepted with an executionId to poll. ```bash curl -sS -X POST "https://api.admanage.ai/v1/automations/execute" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"flow":{"nodes":[{"id":"node-action-1","type":"action","service":"webhook","event":"Send Webhook","config":{"url":"https://example.test/webhook","method":"POST","headers":[{"key":"Content-Type","value":"application/json"}],"body":"{\"text\":\"Automation fired\"}"},"position":1}]},"actionType":"webhook","accountId":"act_123456789","dryRun":true}' ``` ```json { "success": true, "data": { "executionId": 103, "status": "running", "message": "Poll GET /v1/automations/executions/103 for status." } } ``` ### List Executions - GET /v1/automations/executions Query: page, limit, status ("running"|"completed"|"failed"|"scheduled_delay"|"awaiting_approval"), automationRuleId, workspaceId ```bash curl -sS "https://api.admanage.ai/v1/automations/executions?page=1&limit=10&status=completed" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": [ { "id": 101, "automationRuleId": 1, "name": "Pause low ROAS ads", "actionType": "pause_ad", "status": "completed", "executedAt": "2026-02-26T09:00:05.000Z", "completedAt": "2026-02-26T09:00:12.000Z", "duration": 7000, "errorMessage": null, "workspaceId": "workspace_abc" } ], "pagination": { "page": 1, "limit": 10, "total": 1, "totalPages": 1 } } ``` ### Get Execution Details - GET /v1/automations/executions/:id Returns full execution with stepResults, executionLogs, flow, and any delayedExecution or approval records. ```bash curl -sS "https://api.admanage.ai/v1/automations/executions/101" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": { "id": 101, "automationRuleId": 1, "name": "Pause low ROAS ads", "actionType": "pause_ad", "accountId": "act_123456789", "flow": { "nodes": [] }, "status": "completed", "executedAt": "2026-02-26T09:00:05.000Z", "completedAt": "2026-02-26T09:00:12.000Z", "duration": 7000, "stepResults": [ { "nodeId": "action-1", "status": "success", "result": { "adsPaused": 3 } } ], "executionLogs": [ "Evaluating trigger...", "Running action: pause_ad", "Paused 3 ads" ], "errorMessage": null, "delayedExecution": null, "approval": null } } ``` Notes: - Execute endpoints return HTTP 202 Accepted. Most automations complete in seconds — poll the execution endpoint for final status. - Status values: "running", "completed", "failed", "scheduled_delay" (waiting for delay node), "awaiting_approval" (pending human approval). - Inline execute (POST /v1/automations/execute) runs a flow without saving it as a rule. Useful for one-off or CI-triggered automation. - dryRun: true will simulate the execution without making real changes (supported on inline execute). - All queries are scoped to the company associated with your API key. ### Preview Trigger - GET /v1/automations/preview-trigger Preview which ads/ad sets would match an automation rule's trigger conditions. Useful for testing rules before activating. Query: accountId (required), criteria? (JSON: { metric, operator, value, lookbackDays }), adSetFilterType?, adSetNameFilter?, adStatusFilter?, minSpendFilter?, workspaceId? ## Activity Log (Change-Log Export) Every mutation performed through AdManage — launches, duplications, status flips, budget/bidding updates, edits, media uploads, deletes, and automation runs — is captured in the activity log. Use this to correlate platform changes with performance shifts or audit who changed what. ### GET /v1/activity Query: page?, limit? (max 100), companyId? or company? (required for external keys; use company_id from /v1/accounts), userId? (matches userId or partial userEmail), platform?, status?, action? (one value or comma-separated values), accountId?, workspaceId?, startDate?, endDate? ```bash curl -sS "https://api.admanage.ai/v1/activity?platform=meta&status=success&action=launch_ads&startDate=2026-04-01&endDate=2026-04-21&limit=25" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": [ { "id": 918273, "action": "launch_ads", "status": "success", "platform": "meta", "userEmail": "ada@customer.com", "userId": "clx123abc", "accountId": "act_123456789", "name": "Spring 2026 — Video Ads", "businessName": "Acme Brand", "sourceIds": [], "destinationIds": ["120249137908810789"], "itemsAttempted": 1, "itemsSucceeded": 1, "itemsFailed": 0, "createdAt": "2026-04-21T14:02:53.000Z", "workspaceId": "workspace_abc", "thumbnails": [{ "name": "creative.mp4", "preview": "https://media.admanage.ai/acme/creative.jpg" }], "error": null } ], "pagination": { "page": 1, "limit": 25, "total": 342, "totalPages": 14 } } ``` Notes: - Platform values: meta, tiktok, snapchat, pinterest, taboola, axon, google_ads, reddit, linkedin. - Status values: success, failed, partial, attempted. - Common actions: launch_ads, duplicate_campaign, duplicate_adset, duplicate_ad, update_status, update_budget, update_bidding, update_name, disable_app_events, edit_ads, upload_media, delete_entities, adscan_scroll, adscan_board_save. - action accepts one value or a comma-separated list. External API keys require activity:read or csm:read and must pass companyId (company is accepted as an alias); customer API keys remain scoped to their own company. - startDate / endDate accept YYYY-MM-DD or full ISO-8601. - Sorted by createdAt desc. ### GET /v1/activity/:id Get the full payload for a single entry (inputData, outputData, items, details, thumbnails, error). Use after listing to drill into a specific change. Activity-scoped external keys must also pass the same company as a query parameter. ```bash curl -sS "https://api.admanage.ai/v1/activity/918273" \ -H "Authorization: Bearer " ``` ## Launch Defaults Get saved defaults for an ad account — Facebook Page, Instagram, ad copy, CTA, link, UTM tags, naming convention. Call this before launching to pre-fill values. ### GET /v1/launch-defaults Query parameters: | Param | Required | Description | |-------|----------|-------------| | accountId | no | Ad account ID (e.g. "act_123"). If omitted, uses the user's default ad account | | workspaceId | no | Workspace ID. If omitted, uses the user's default workspace | ```bash curl -sS "https://api.admanage.ai/v1/launch-defaults" \ -H "Authorization: Bearer " # With specific account curl -sS "https://api.admanage.ai/v1/launch-defaults?accountId=act_384730851257635" \ -H "Authorization: Bearer " ``` ```json { "success": true, "data": { "accountId": "act_384730851257635", "accountName": "Admanage Limited", "platform": "facebook", "workspaceId": "workspace_abc", "defaults": { "page": "470703006115773", "facebookName": "Admanage", "insta": "17841471826052348", "instaName": "admanage.official", "title": "Stop wasting time on ad management", "description": "Launch ads 10x faster with AdManage", "cta": "LEARN_MORE", "link": "https://admanage.ai/", "displaylink": "admanage.ai", "urlTags": "utm_source=facebook&utm_medium=paid", "naming": "{{campaign}} | {{adset}} | {{creative}}", "namingSeparator": " | ", "launchPaused": false } } } ``` ### PATCH /v1/launch-defaults Update saved launch defaults for an ad account. All fields are optional — only provided fields are updated. Body fields: accountId?, page?, insta?, facebookName?, instaName?, title?, description?, adDescription?, cta?, link?, displaylink?, urlTags?, naming?, namingSeparator?, launchPaused?, enhancedCreative?, multiAdvertiser?, instagramOnly?, scalePostId?, adCreationCutoff? ```bash curl -sS -X PATCH "https://api.admanage.ai/v1/launch-defaults" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"accountId":"act_384730851257635","title":"New default headline","cta":"SHOP_NOW","launchPaused":true}' ``` ```json { "success": true, "message": "Updated 3 setting(s) for act_384730851257635", "updated": { "title": "New default headline", "cta": "SHOP_NOW", "launchPaused": true } } ``` ## Ad Formats (Carousel, Multi-Placement, Flexible) The `type` field in each ad controls the format. Here are details for advanced formats: ### Carousel (type: "carousel") Meta only. 2-10 cards. Each media item becomes one card and must include `carouselTitle`. `carouselDescription` and `carouselLink` are optional; `carouselLink` falls back to the ad-level `link` when omitted. Card order follows the `media` array, and `carouselIndex` is optional metadata if you want to label positions explicitly. Important: `page` and `insta` are raw ID strings. Passing `page: { "id": "..." }` will fail at Meta creative creation. `facebookName` and `instaName` are optional display labels; pass them from `GET /v1/launch-defaults` or `GET /v1/profiles` when available. Each media item can include per-card fields: | Field | Description | |-------|-------------| | carouselTitle | Per-card headline | | carouselDescription | Per-card description | | carouselLink | Per-card click-through URL | | carouselIndex | Card position (0-based) | | portraitVariation | Optional vertical/Reels/Stories variant for this card. Same shape as a media object; pass url, name/type/mimeType, and width+height or dimension when available | ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [{ "adAccountId": "act_384730851257635", "type": "carousel", "title": "Our Best Products", "cta": "SHOP_NOW", "link": "https://example.com/", "launchPaused": true, "page": "470703006115773", "facebookName": "Admanage", "insta": "17841471826052348", "instaName": "admanage.official", "adSets": [{ "value": "120248289622780456", "label": "US Broad" }], "media": [ { "url": "https://media.admanage.ai/acme/card1.png", "carouselTitle": "Product A", "carouselDescription": "Best seller", "carouselLink": "https://example.com/a", "carouselIndex": 0 }, { "url": "https://media.admanage.ai/acme/card2.png", "carouselTitle": "Product B", "carouselDescription": "New arrival", "carouselLink": "https://example.com/b", "carouselIndex": 1, "portraitVariation": { "url": "https://media.admanage.ai/acme/card2-story.png", "type": "image", "width": 1080, "height": 1920 } }, { "url": "https://media.admanage.ai/acme/card3.mp4", "carouselTitle": "Product C", "carouselIndex": 2 } ] }] }' ``` ### Catalogue Ads / Show Products (Meta) Meta catalogue support uses `catalogueAdConfig` internally. For API callers, the simplest manual "Show Products" shape is to pass flat fields on the ad. Required for manual Show Products: - `showProducts: true` - `catalogueId` or `catalogId` - `productSetId` - Meta identity strings: `page` and `insta` - Usual launch inputs: `adAccountId`, `adSets`, `media`, `link` ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [{ "adAccountId": "act_384730851257635", "type": "multi", "title": "Shop the collection", "cta": "SHOP_NOW", "link": "https://example.com/", "launchPaused": true, "page": "470703006115773", "insta": "17841471826052348", "adSets": [{ "value": "120248289622780456", "label": "US Sales" }], "media": [ { "url": "https://media.admanage.ai/acme/feed.png", "width": 1080, "height": 1350 }, { "url": "https://media.admanage.ai/acme/story.png", "width": 1080, "height": 1920 } ], "showProducts": true, "catalogueId": "catalog_123", "catalogueName": "Linjer Catalog", "productSetId": "set_456", "productSetName": "Best Sellers" }] }' ``` Full object form is also accepted: ```json { "catalogueAdConfig": { "enabled": true, "formatMode": "manual", "format": "SINGLE_IMAGE", "selectedCatalogue": { "id": "catalog_123", "name": "Linjer Catalog" }, "selectedProductSet": { "id": "set_456", "name": "Best Sellers" }, "includeCarouselForCatalogue": true } } ``` `formatMode: "manual"` adds products to supplied creatives. `formatMode: "automatic"` uses Advantage+ catalogue generation and requires `selectedCatalogue.id` plus `format`; pass `selectedProductSet.id` when targeting a specific set. Hunch-style/local-inventory single-image catalog lead ads use automatic mode with no uploaded media. This creates the single catalog image `template_data` payload with root `product_set_id` and no `asset_feed_spec`. ```json { "adAccountId": "act_384730851257635", "type": "single", "launchPaused": true, "page": "470703006115773", "insta": "17841471826052348", "media": [], "adSets": [{ "value": "120253835413950456", "label": "New Leads Ad Set" }], "selectedLeadForm": { "id": "1307134354292947", "name": "Hello new" }, "catalogueAdConfig": { "enabled": true, "formatMode": "automatic", "format": "SINGLE_IMAGE", "localInventorySingleImage": true, "selectedCatalogue": { "id": "4007920146182674", "name": "WINDOWS US", "vertical": "commerce" }, "selectedProductSet": { "id": "1330629288998733", "name": "windows b" }, "dynamicMedia": { "optimizedMediaSelection": true, "automaticVideoCroppingEnabled": true, "prioritizeVideo": false } } } ``` ### Multi-Placement (type: "multi") 2+ format variants (square, vertical, landscape) in ONE ad. Facebook auto-picks the best per placement: ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [{ "adAccountId": "act_384730851257635", "type": "multi", "title": "Spring Campaign", "cta": "LEARN_MORE", "link": "https://example.com/", "page": "470703006115773", "adSets": [{ "value": "120248289622780456", "label": "US Broad" }], "media": [ { "url": "https://media.admanage.ai/acme/square-1x1.mp4" }, { "url": "https://media.admanage.ai/acme/vertical-9x16.mp4" } ] }] }' ``` ### Flexible / Advantage+ (type: "flexible") Meta only. 1+ media items. Multiple headline and body variations are optional; Facebook generates optimal combinations from the provided media plus `headlineVariations` / `bodyVariations`. If the variation arrays are omitted, Meta falls back to the top-level `title` and `description`. ```bash curl -sS -X POST "https://api.admanage.ai/v1/launch" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "ads": [{ "adAccountId": "act_384730851257635", "type": "flexible", "title": "Fallback headline", "description": "Fallback body", "cta": "LEARN_MORE", "link": "https://example.com/", "page": "470703006115773", "insta": "17841471826052348", "headlineVariations": ["Stop wasting time", "Launch ads 10x faster", "The ad tool you need"], "bodyVariations": ["Try AdManage free", "Used by 500+ brands", "No credit card required"], "adSets": [{ "value": "120248289622780456", "label": "US Broad" }], "media": [ { "url": "https://media.admanage.ai/acme/creative-1.mp4" }, { "url": "https://media.admanage.ai/acme/creative-2.jpg" } ] }] }' ``` ## AdScan Compatibility Wrapper Use your AdManage API key to call AdScan's public tRPC API through AdManage. This wrapper forwards requests to AdScan, automatically injects the authenticated AdManage user email, and preserves AdScan's response shape. Base path: ``` /v1/adscan/trpc/. ``` Supported methods: - GET for AdScan queries such as `boards.list`, `ads.list`, `ads.getDetails`, `brandSpy.getOverview`, and `brandSpy.listTopAdvertisers` - POST for AdScan mutations such as `boards.create`, `ads.addToBoard`, `companies.follow`, and `notifications.upsertRule` ### GET /v1/adscan/trpc/{procedure} Pass AdScan query input through the standard `input` query parameter. The JSON must be URL-encoded. For `ads.list`, AdManage adds a convenience alias for spend-based saved-ad filtering: - `spend` → shorthand for `spendMin` - `spendMin` → converted to `viewsMin` - `spendMax` → converted to `viewsMax` Conversion rule: - assumed CPM = **$13** - `views = spend * 1000 / 13` ```bash # List boards curl -sS "https://api.admanage.ai/v1/adscan/trpc/boards.list" \ -H "Authorization: Bearer " # Search saved ads curl -sS "https://api.admanage.ai/v1/adscan/trpc/ads.list?input=%7B%22limit%22%3A5%2C%22boardId%22%3A%22ALL%22%7D" \ -H "Authorization: Bearer " # Search saved ads using spend alias (260 USD ~= 20,000 views at $13 CPM) curl -sS "https://api.admanage.ai/v1/adscan/trpc/ads.list?input=%7B%22searchQuery%22%3A%22crypto%22%2C%22spendMin%22%3A260%2C%22limit%22%3A10%7D" \ -H "Authorization: Bearer " # Brand Spy overview curl -sS "https://api.admanage.ai/v1/adscan/trpc/brandSpy.getOverview?input=%7B%22companyName%22%3A%22nike.com%22%2C%22status%22%3A%22active%22%7D" \ -H "Authorization: Bearer " ``` ```json { "result": { "data": { "stats": { "totalAds": 322, "totalReach": 1500000 } } } } ``` ### POST /v1/adscan/trpc/{procedure} Pass the exact JSON body expected by the AdScan mutation. ```bash # Create a board curl -sS -X POST "https://api.admanage.ai/v1/adscan/trpc/boards.create" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"name":"Competitor Winners"}' # Save an ad to a board curl -sS -X POST "https://api.admanage.ai/v1/adscan/trpc/ads.addToBoard" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"adHash":"abc123","boardId":42}' ``` ```json { "result": { "data": { "id": 42, "name": "Competitor Winners" } } } ``` ### POST /v1/adscan/ad-library/search Run a live Meta Ads Library keyword/page/url search through AdScan. This is read-only and returns detailed `ads[]` records with copy, cards, page metadata, metrics, media previews, and optional raw `collatedResults` for ingestion. ```bash curl -sS -X POST "https://api.admanage.ai/v1/adscan/ad-library/search" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "keyword": "creative", "country": "GB", "active_status": "active", "media_type": "all", "search_type": "keyword_exact_phrase", "limit": 30, "includeViews": true, "includeRaw": true }' ``` Views are returned at `ads[].metrics.views` when Meta publishes reach-transparency data for the selected country. GB/EU countries enable this automatically; US generally does not publish views in this same details endpoint. ```json { "ok": true, "count": 2, "search": { "label": "creative", "limit": 30, "includeViews": true }, "ads": [ { "adArchiveId": "2630515643996116", "pageName": "Gorillaz", "copy": { "body": "The recording of The Mountain", "caption": "www.instagram.com", "ctaText": "Watch more", "linkUrl": "https://www.instagram.com/gorillaz/reels/" }, "metrics": { "views": 10256, "reach": 10256, "publisherPlatforms": ["INSTAGRAM"] }, "media": [{ "type": "video", "url": "https://video.xx.fbcdn.net/v/example.mp4" }] } ], "collatedResults": ["raw result objects for ingest"] } ``` ### POST /v1/adscan/ad-library/ingest Download media and ingest raw results from `/v1/adscan/ad-library/search`. This performs writes/uploads and requires a read/write key. ```bash curl -sS -X POST "https://api.admanage.ai/v1/adscan/ad-library/ingest" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "collatedResults": [/* collatedResults array from search */], "rankCountry": "GB", "rankTotal": 30 }' ``` ## Top Ads (Performance) Get top performing ads by spend, sorted by a metric. ### GET /v1/analytics/top-ads Query parameters: | Param | Required | Description | |-------|----------|-------------| | accountIds | yes | Comma-separated ad account IDs | | startDate | yes | Start date (YYYY-MM-DD) | | endDate | yes | End date (YYYY-MM-DD) | | campaignIds | no | Comma-separated campaign IDs to filter | | adSetIds | no | Comma-separated ad set IDs to filter | | adType | no | Filter by type: "video", "image", "carousel" | | limit | no | Max results (default 10, max 50) | | page | no | Page number (default 1) | | workspaceId | no | Workspace ID | ```bash curl -sS "https://api.admanage.ai/v1/analytics/top-ads?accountIds=act_384730851257635&startDate=2026-03-01&endDate=2026-03-20&limit=5" \ -H "Authorization: Bearer " ``` ## Media (Search + Upload) Search uploaded media files and upload new media from URL or file. ### GET /v1/media/search Search media files by name, type, or other criteria. Proxied to the main AdManage API. ```bash curl -sS "https://api.admanage.ai/v1/media/search?query=spring&type=video" \ -H "Authorization: Bearer " ``` ### GET /v1/media/:id Get details of a specific media file. ```bash curl -sS "https://api.admanage.ai/v1/media/12345" \ -H "Authorization: Bearer " ``` ### POST /v1/media/upload/url Upload media from a public URL to the AdManage library. Body: { url } ```bash curl -sS -X POST "https://api.admanage.ai/v1/media/upload/url" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com/video.mp4"}' ``` ### POST /v1/media/upload Upload a local file via multipart/form-data. ```bash curl -sS -X POST "https://api.admanage.ai/v1/media/upload" \ -H "Authorization: Bearer " \ -F "file=@/path/to/creative.mp4" ``` ### POST /v1/media/subtitles Start a subtitle render job for a hosted video. Provide timed `segments`, `srtText`, or `srtUrl`; if omitted, the media service attempts auto-transcription. Backpressure: each company can have up to 3 active subtitle jobs by default, tracked through the existing Redis limiter with in-memory fallback. Extra submissions return 429 until existing jobs finish or expire from tracking. After a jobId exists, do not resubmit the same render. Poll GET /v1/media/subtitles/{jobId} or use the MCP wait_for_subtitled_video helper. ```bash curl -sS -X POST "https://api.admanage.ai/v1/media/subtitles" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"videoUrl":"https://media.admanage.ai/acme/source.mp4","segments":[{"start":0,"end":1.2,"text":"Launch faster"}],"stylePreset":"bold"}' ``` Then poll GET /v1/media/subtitles/:jobId and publish with POST /v1/media/subtitles/:jobId/publish to get the final media.admanage.ai MP4. ## Cloud Storage (Google Drive + Dropbox + OneDrive) Browse files in connected Google Drive, Dropbox, and OneDrive accounts for launching. ### GET /v1/drive/browse Browse Google Drive folders and files. Query parameters: | Param | Required | Description | |-------|----------|-------------| | folderId | no | Google Drive folder ID (default: "root") | | scope | no | "my-drive" (default) or "shared-with-me" | | search | no | Search query for file names | | pageSize | no | Results per page (default 100) | | pageToken | no | Pagination token from previous response | | workspaceId | no | Workspace ID (auto-detected from user if omitted) | ```bash # Browse root folder curl -sS "https://api.admanage.ai/v1/drive/browse" \ -H "Authorization: Bearer " # Browse a specific folder curl -sS "https://api.admanage.ai/v1/drive/browse?folderId=1ABcDeFgHiJkLmNoP" \ -H "Authorization: Bearer " # Search for files curl -sS "https://api.admanage.ai/v1/drive/browse?search=spring%20campaign" \ -H "Authorization: Bearer " ``` ### GET /v1/dropbox/browse Browse Dropbox folders and shared links. Query parameters: | Param | Required | Description | |-------|----------|-------------| | path | no | Dropbox folder path (default: root "") | | sharedLink | no | Dropbox shared folder/file link URL | | search | no | Search query for file names | | limit | no | Results per page (default 100) | | workspaceId | no | Workspace ID (auto-detected from user if omitted) | ```bash # Browse root folder curl -sS "https://api.admanage.ai/v1/dropbox/browse" \ -H "Authorization: Bearer " # Browse a subfolder curl -sS "https://api.admanage.ai/v1/dropbox/browse?path=/Marketing/Creatives" \ -H "Authorization: Bearer " # Browse a shared folder link curl -sS "https://api.admanage.ai/v1/dropbox/browse?sharedLink=https://www.dropbox.com/scl/fo/abc123/AABcDE" \ -H "Authorization: Bearer " ``` Each file in the response includes a `launchUrl` — pass this directly as the `url` in media[] when launching ads. ### GET /v1/onedrive/browse Browse OneDrive folders and files. Query parameters: | Param | Required | Description | |-------|----------|-------------| | nodeId | no | OneDrive node ID from a previous folder result (default: "root") | | search | no | Search query for file names | | includeMediaOnly | no | "true" (default) to show media files and folders, "false" for all files | | pageSize | no | Results per page (default 100, max 200) | | workspaceId | no | Workspace ID (auto-detected from user if omitted) | ```bash # Browse My OneDrive root curl -sS "https://api.admanage.ai/v1/onedrive/browse" \ -H "Authorization: Bearer " # Browse a folder returned by a previous response curl -sS "https://api.admanage.ai/v1/onedrive/browse?nodeId=" \ -H "Authorization: Bearer " # Search for files curl -sS "https://api.admanage.ai/v1/onedrive/browse?search=spring%20campaign" \ -H "Authorization: Bearer " ``` OneDrive file responses include `downloadUrl` and `launchUrl` values from Microsoft Graph. These URLs are short-lived, so use them promptly. ## MCP Server (Model Context Protocol) AdManage provides an MCP server for AI assistants like Claude. It exposes the core launch, media, reporting, automation, and management workflows as MCP tools, including dedicated Google Ads launch tools. ### Remote (Claude.ai / Claude Desktop / Claude Code) ```bash claude mcp add --transport http admanage https://mcp.admanage.ai/mcp \ --header "Authorization: Bearer ak_your_api_key" ``` ### Local (Claude Code — stdio) ```bash claude mcp add admanage \ --transport stdio \ -- npx tsx packages/mcp-admanage/src/index.ts \ --env ADMANAGE_API_KEY=your_api_key \ --env ADMANAGE_API_URL=https://api.admanage.ai ``` Endpoints: - MCP: https://mcp.admanage.ai/mcp - Health: https://mcp.admanage.ai/health - Docs: https://api.admanage.ai/llms.txt