{"openapi":"3.1.0","info":{"title":"AutoAdy REST API","version":"1.0.0","summary":"Meta ads analysis, creative generation, and ad writes over plain HTTP.","description":"One POST endpoint per tool, under `/api/mcp/{tool}`. Send an AutoAdy API key as\n`Authorization: Bearer adk_...` and a JSON body. There is no query-parameter or\ncookie authentication.\n\n**Creating a key** — in the AutoAdy app, Settings → API Keys. Up to 3 active keys.\nThe plaintext key is shown once, at creation; AutoAdy only stores its SHA-256 hash.\n\n**Response shape** — successful results are wrapped:\n\n```json\n{ \"source\": \"AutoAdy — AI Meta Ads Optimization (autoady.io)\", \"data\": { } }\n```\n\nMost errors use that same wrapper with a non-2xx status and the message under\n`data.error`. Three do not, and clients must handle both shapes:\n\n| Status | Body |\n| --- | --- |\n| 401 — key missing, malformed, revoked or expired | bare `{ \"error\": \"...\" }` |\n| 429 — over the request limit | bare `{ \"error\": \"...\" }` |\n| 503 — rate-limiting backend degraded | bare `{ \"error\": \"...\" }` |\n| everything else | wrapped `{ \"source\", \"data\" }` |\n\nA **207** means a multi-step write applied only partially. It is not a success —\nbranch on the status code, not on `response.ok`.\n\nA few tools also report soft failures **inside a 200** — `benchmarks`, `compare`,\n`fatigue` and `get-skill` answer an unknown input with `data.error` rather than a\n4xx. Check `data.error` as well as the status on those four.\n\n**Rate limit** — 60 requests per minute per API key. A 429 carries\n`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After`.\nA 503 means AutoAdy's rate-limiting backend is degraded, not that you were limited.\n\n**Plans** — read tools and the skill tools work on every plan. Copy generation,\ncreative pushes and the creative workflow pipelines require Pro or Agency and\nanswer 403 with an `upgrade_url` otherwise.\n\n**Long-running calls** — creative workflows can take minutes. Allow up to a\n300-second timeout.\n\nThe same tools are also reachable over the Model Context Protocol at\n`https://www.autoady.io/api/mcp`, which additionally supports OAuth 2.1.","contact":{"name":"AutoAdy support","email":"contact@autoady.io","url":"https://www.autoady.io/contact"},"termsOfService":"https://www.autoady.io/terms"},"servers":[{"url":"https://www.autoady.io","description":"Production"}],"security":[{"ApiKeyBearer":[]}],"tags":[{"name":"Tools","description":"Every tool is a POST to /api/mcp/{tool} with a JSON body and a bearer API key."}],"externalDocs":{"description":"Developer documentation","url":"https://www.autoady.io/docs"},"paths":{"/api/mcp/list-accounts":{"post":{"operationId":"listAccounts","summary":"List reachable ad accounts","tags":["Tools"],"description":"Returns every Meta ad account this API key's workspace can act on, with id, name and currency. Call this first — the `account_id` values it returns are the only ones the other tools accept. The request body is ignored; send `{}`.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{}},"example":{}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"type":"object","required":["accounts"],"properties":{"accounts":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Accounts reachable by this key."}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/results":{"post":{"operationId":"results","summary":"Live performance results","tags":["Tools"],"description":"Live Meta delivery numbers for one account — spend, results, CPA/CPL, CTR, CPM — aggregated at the level you ask for. Figures come from the Meta Marketing API through AutoAdy's conversion-counting layer, so they match what the app shows.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Omit to use the workspace's currently active account. Use the `list-accounts` tool to see what this key can reach.","examples":["act_1234567890"]},"level":{"type":"string","enum":["account","campaign","adset","ad"],"default":"campaign","description":"Breakdown level for the returned rows."},"date_preset":{"type":"string","enum":["today","yesterday","last_3d","last_7d","last_14d","last_30d","last_90d","this_month","last_month"],"default":"last_7d","description":"Reporting window. Mutually exclusive with since/until."},"since":{"type":"string","description":"Start of a custom window, ISO YYYY-MM-DD. Use with until instead of date_preset."},"until":{"type":"string","description":"End of a custom window, ISO YYYY-MM-DD. Required whenever since is set."}}},"example":{"account_id":"act_1234567890","level":"campaign","date_preset":"last_7d"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/health":{"post":{"operationId":"health","summary":"Account health score","tags":["Tools"],"description":"Scores the account across delivery, efficiency, creative freshness and structure, and returns the component scores behind the headline number. Uses the active account when `account_id` is omitted.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Omit to use the workspace's currently active account. Use the `list-accounts` tool to see what this key can reach.","examples":["act_1234567890"]}}},"example":{"account_id":"act_1234567890"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/winner-insights":{"post":{"operationId":"winnerInsights","summary":"What the winning ads have in common","tags":["Tools"],"description":"Analyses the account's top performers and reports the patterns they share — formats, hooks, angles, and the creative traits that correlate with results. Uses the active account when `account_id` is omitted.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Omit to use the workspace's currently active account. Use the `list-accounts` tool to see what this key can reach.","examples":["act_1234567890"]}}},"example":{"account_id":"act_1234567890"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/fatigue-alerts":{"post":{"operationId":"fatigueAlerts","summary":"Creative fatigue alerts","tags":["Tools"],"description":"Flags ads whose frequency is climbing while CTR decays — the ones that need rotating before they burn budget. Uses the active account when `account_id` is omitted.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Omit to use the workspace's currently active account. Use the `list-accounts` tool to see what this key can reach.","examples":["act_1234567890"]},"quick":{"type":"boolean","default":false,"description":"Run the fast, shallower pass. Only the literal JSON boolean `true` enables it — the string `\"true\"` does not."}}},"example":{"account_id":"act_1234567890","quick":true}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/benchmarks":{"post":{"operationId":"benchmarks","summary":"Industry benchmarks","tags":["Tools"],"description":"Returns AutoAdy's Meta ads benchmarks (CPM, CTR, CPA) for one industry, or for every industry when `niche` is omitted. Pure lookup — it touches no ad account and needs no Meta connection.\n\nNote: an unrecognised `niche` still answers **HTTP 200**, with `data.error` naming the available niches. Check `data.error` as well as the status.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"niche":{"type":"string","description":"Industry slug, e.g. `ecommerce`. Omit to receive the full benchmark set — which is also how you discover the valid slugs."}}},"example":{"niche":"ecommerce"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/compare":{"post":{"operationId":"compare","summary":"Compare your metrics to a benchmark","tags":["Tools"],"description":"Scores your CPM, CTR and/or CPL against the benchmark for a niche and says whether each is ahead or behind. Supply at least one of the three metrics. Pure calculation — no ad account is read.\n\nNote: a missing or unknown `niche`, or no metric at all, still answers **HTTP 200** with `data.error`.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["niche"],"properties":{"niche":{"type":"string","description":"Industry slug, as returned by the `benchmarks` tool."},"your_cpm":{"type":"number","description":"Your cost per 1,000 impressions. Lower is better."},"your_ctr":{"type":"number","description":"Your click-through rate, in percent. Higher is better."},"your_cpl":{"type":"number","description":"Your cost per lead, compared against the benchmark CPA."}}},"example":{"niche":"ecommerce","your_cpm":12.4,"your_ctr":1.8}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/fatigue":{"post":{"operationId":"fatigue","summary":"Score creative fatigue from your own numbers","tags":["Tools"],"description":"Given a frequency, a CTR trend and a run length, returns a fatigue verdict and what to do about it. Pure calculation on the numbers you pass — use `fatigue-alerts` instead if you want AutoAdy to pull the numbers from a live account.\n\nNote: validation failures answer **HTTP 200** with `data.error`.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["frequency","ctr_trend","days_running"],"properties":{"frequency":{"type":"number","minimum":0,"description":"Current average impressions per person."},"ctr_trend":{"type":"array","items":{"type":"number"},"minItems":2,"description":"CTR readings in chronological order, oldest first. At least two values."},"days_running":{"type":"number","minimum":0,"description":"Days the creative has been live."}}},"example":{"frequency":3.4,"ctr_trend":[2.1,1.8,1.4,1.1],"days_running":21}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/ad-copy":{"post":{"operationId":"adCopy","summary":"Generate Meta ad copy","tags":["Tools"],"description":"Writes primary text, headlines and descriptions for a Meta ad. Give it either a `url` to read the offer from, or a `description` you write yourself — at least one is required.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["objective"],"anyOf":[{"required":["url"]},{"required":["description"]}],"properties":{"url":{"type":"string","format":"uri","description":"Product or landing page to read the offer from. Scheme optional."},"description":{"type":"string","maxLength":2000,"description":"Describe the offer yourself instead of passing a URL. Max 2,000 characters."},"objective":{"type":"string","enum":["Leads","Purchases","Awareness","Sign Ups"],"description":"Campaign objective. Case-sensitive — these exact strings."},"tone":{"type":"string","enum":["Professional","Casual","Urgent","Fun","Bold"],"default":"Professional","description":"Voice for the copy."}}},"example":{"url":"https://example.com/product","objective":"Purchases","tone":"Bold"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"The page at `url` could not be scraped, or yielded too little text to work from. Pass `description` instead. Wrapped error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WrappedError"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/hooks":{"post":{"operationId":"hooks","summary":"Generate scroll-stopping hooks","tags":["Tools"],"description":"Produces opening lines and hook concepts for video or static ads. Give it either a `url` or a `description` — at least one is required.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"anyOf":[{"required":["url"]},{"required":["description"]}],"properties":{"url":{"type":"string","format":"uri","description":"Product or landing page to read the offer from. Scheme optional."},"description":{"type":"string","maxLength":1000,"description":"Describe the offer yourself instead of passing a URL. Max 1,000 characters."},"platform":{"type":"string","enum":["both","facebook","instagram","tiktok"],"default":"both","description":"Platform to tune the hooks for. `both` means Facebook and Instagram."}}},"example":{"description":"A 12-week strength program for runners over 40","platform":"instagram"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"The page at `url` could not be scraped, or yielded too little text to work from. Pass `description` instead. Wrapped error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WrappedError"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"502":{"$ref":"#/components/responses/BadGateway"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/save-creative":{"post":{"operationId":"saveCreative","summary":"Save images to the creative library","tags":["Tools"],"description":"Stores externally generated images in the AutoAdy creative library so they can be pushed to an ad set later. Supply `image_urls` (up to 10) or a single `image_url`.\n\nURLs must be public `http`/`https`. Loopback, link-local and private-range hosts are rejected.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"anyOf":[{"required":["image_urls"]},{"required":["image_url"]}],"properties":{"image_urls":{"type":"array","items":{"type":"string","format":"uri"},"minItems":1,"maxItems":10,"description":"Publicly reachable image URLs. At most 10 per call."},"image_url":{"type":"string","format":"uri","description":"Single-image shorthand. Only read when `image_urls` is not an array."},"prompt":{"type":"string","default":"External upload","description":"Prompt or note stored alongside the images."},"aspect_ratio":{"type":"string","default":"1:1","description":"Aspect-ratio label stored as metadata. Free-form — not validated. The app's own values are `1:1`, `9:16` and `4:5`."},"resolution":{"type":"string","default":"2K","description":"Resolution label stored as metadata. Free-form — not validated."}}},"example":{"image_urls":["https://cdn.example.com/creative-a.png"],"prompt":"Winter promo, bold typography","aspect_ratio":"4:5"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/push-creative":{"post":{"operationId":"pushCreative","summary":"Push a creative live into an ad set","tags":["Tools"],"description":"Uploads an image or video to Meta, builds the creative, and creates an ad inside an existing ad set. This is a real write against the ad account.\n\nRequirements: exactly one of `image_url` / `video_url`, and exactly one destination (`website_url` or `lead_gen_form_id`). Media URLs must be public `http`/`https`; private and loopback hosts are rejected.\n\n`request_id` is a caller-chosen idempotency key — reusing one returns the original outcome instead of creating a second ad. Ads are created **PAUSED** unless `status` is `\"ACTIVE\"`, and going straight to ACTIVE additionally requires `hard_confirm_text`.\n\nWrites are metered per ad account (200 per hour) on top of the per-key request limit.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["account_id","request_id","adset_id"],"anyOf":[{"required":["image_url"]},{"required":["video_url"]}],"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Required for this tool.","examples":["act_1234567890"]},"request_id":{"type":"string","description":"Caller-generated idempotency key. Reuse it to retry safely."},"adset_id":{"type":"string","description":"Existing ad set to create the ad in."},"image_url":{"type":"string","format":"uri","description":"Public image URL. Mutually exclusive with `video_url`."},"video_url":{"type":"string","format":"uri","description":"Public video URL. AutoAdy uploads it and waits for Meta to finish processing; a video still processing after ~90 seconds fails the call."},"thumbnail_url":{"type":"string","format":"uri","description":"Thumbnail for a video ad."},"primary_text":{"type":"string","description":"Ad body text."},"headline":{"type":"string","description":"Ad headline."},"ad_name":{"type":"string","description":"Name for the new ad. Defaults to `Studio Ad <timestamp>`."},"cta_type":{"type":"string","description":"Meta call-to-action type, passed through unvalidated — any value Meta accepts works. Common ones: `LEARN_MORE`, `SIGN_UP`, `GET_QUOTE`, `CONTACT_US`. Defaults to `LEARN_MORE` for video ads and for lead-form image ads.","examples":["LEARN_MORE","SIGN_UP","GET_QUOTE","CONTACT_US"]},"website_url":{"type":"string","format":"uri","description":"Destination for a traffic/conversion ad. Alternative to `lead_gen_form_id`."},"lead_gen_form_id":{"type":"string","description":"Instant-form id for a lead ad. Alternative to `website_url`."},"fb_page_id":{"type":"string","description":"Facebook page to publish as. Resolved automatically when omitted."},"ig_page_id":{"type":"string","description":"Instagram account to publish as."},"beneficiary":{"type":"string","description":"EU ad-label beneficiary."},"payer":{"type":"string","description":"EU ad-label payer."},"status":{"type":"string","enum":["PAUSED","ACTIVE"],"default":"PAUSED","description":"Anything other than the exact string `ACTIVE` is treated as `PAUSED`."},"hard_confirm_text":{"type":"string","description":"Required only when `status` is `ACTIVE` — the write boundary refuses to launch live without it."}}},"example":{"account_id":"act_1234567890","request_id":"push-2026-08-19-001","adset_id":"23851234567890123","image_url":"https://cdn.example.com/creative-a.png","primary_text":"Train smarter, not longer.","headline":"12-week runner strength plan","website_url":"https://example.com/plan","cta_type":"LEARN_MORE","status":"PAUSED"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"207":{"$ref":"#/components/responses/PartialSuccess"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/creative-dna":{"post":{"operationId":"creativeDna","summary":"Extract a brand's creative DNA","tags":["Tools"],"description":"Reads a brand's site and derives its voice, palette, claims and visual signature, then stores that profile so later creative generation stays on-brand.\n\nRuns directly against the account this API key can reach — the same execution path as the MCP server. **404** means no reachable Meta ad account (none connected, or the `account_id` you passed is not one this workspace can act on); **403** means the plan does not cover the tool or the key belongs to a read-only Client Viewer; **400** carries a tool-level failure under `data.error`.\n\nThis workflow writes to the ad account, so it is metered by the per-account write budget and is idempotent on the request body: retrying an identical body replays the first run's result instead of writing twice. To force a genuinely new run of the same input, pass a fresh `request_id`. A run the write boundary refused answers **409**.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["account_id","brand_url"],"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Required for this tool.","examples":["act_1234567890"]},"brand_url":{"type":"string","description":"Brand homepage. A missing scheme is filled in as `https://`."},"brand_name":{"type":"string","description":"Brand name. Detected from the page when omitted."},"request_id":{"type":"string","description":"Caller-generated idempotency key. Reuse it to retry safely; omit it and AutoAdy derives one from the request body, so an identical retry replays rather than writing twice."}}},"example":{"account_id":"act_1234567890","brand_url":"example.com"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"207":{"$ref":"#/components/responses/PartialSuccess"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/analyze-winning-ad":{"post":{"operationId":"analyzeWinningAd","summary":"Break down why one ad is winning","tags":["Tools"],"description":"Deconstructs a single high-performing ad — hook, angle, visual structure, offer framing — into a reusable brief you can build variations from.\n\nRuns directly against the account this API key can reach — the same execution path as the MCP server. **404** means no reachable Meta ad account (none connected, or the `account_id` you passed is not one this workspace can act on); **403** means the plan does not cover the tool or the key belongs to a read-only Client Viewer; **400** carries a tool-level failure under `data.error`.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["account_id","ad_id"],"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Required for this tool.","examples":["act_1234567890"]},"ad_id":{"type":"string","description":"Meta ad id to analyse."}}},"example":{"account_id":"act_1234567890","ad_id":"23851234567890123"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/url-to-ads":{"post":{"operationId":"urlToAds","summary":"Turn a product URL into a batch of ads","tags":["Tools"],"description":"Scrapes a product or landing page and generates a batch of ad creatives across several angles. Generated images consume the account's image quota.\n\nRuns directly against the account this API key can reach — the same execution path as the MCP server. **404** means no reachable Meta ad account (none connected, or the `account_id` you passed is not one this workspace can act on); **403** means the plan does not cover the tool or the key belongs to a read-only Client Viewer; **400** carries a tool-level failure under `data.error`.\n\nThis workflow writes to the ad account, so it is metered by the per-account write budget and is idempotent on the request body: retrying an identical body replays the first run's result instead of writing twice. To force a genuinely new run of the same input, pass a fresh `request_id`. A run the write boundary refused answers **409**.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["account_id","url"],"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Required for this tool.","examples":["act_1234567890"]},"url":{"type":"string","description":"Product or landing page. A missing scheme is filled in as `https://`."},"count":{"type":"integer","default":27,"maximum":50,"description":"How many creatives to generate. Values above 50 are clamped to 50."},"angles":{"type":"array","items":{"type":"string"},"description":"Angles to cover. AutoAdy's own set is `pain`, `gain`, `social_proof`, `authority`, `urgency`, `curiosity`; the value is passed through without validation."},"aspect_ratio":{"type":"string","default":"1:1","description":"Output aspect ratio. AutoAdy generates `1:1`, `9:16` and `4:5`; the value is passed through without validation."},"request_id":{"type":"string","description":"Caller-generated idempotency key. Reuse it to retry safely; omit it and AutoAdy derives one from the request body, so an identical retry replays rather than writing twice."}}},"example":{"account_id":"act_1234567890","url":"https://example.com/product","count":9,"angles":["pain","social_proof"]}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"207":{"$ref":"#/components/responses/PartialSuccess"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/multiply-winner":{"post":{"operationId":"multiplyWinner","summary":"Generate variations of a winning creative","tags":["Tools"],"description":"Takes one proven creative — by `ad_id` or by direct `image_url` — and produces variations that keep what works and change what is worth testing. Generated images consume the account's image quota.\n\nRuns directly against the account this API key can reach — the same execution path as the MCP server. **404** means no reachable Meta ad account (none connected, or the `account_id` you passed is not one this workspace can act on); **403** means the plan does not cover the tool or the key belongs to a read-only Client Viewer; **400** carries a tool-level failure under `data.error`.\n\nThis workflow writes to the ad account, so it is metered by the per-account write budget and is idempotent on the request body: retrying an identical body replays the first run's result instead of writing twice. To force a genuinely new run of the same input, pass a fresh `request_id`. A run the write boundary refused answers **409**.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["account_id"],"anyOf":[{"required":["ad_id"]},{"required":["image_url"]}],"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Required for this tool.","examples":["act_1234567890"]},"ad_id":{"type":"string","description":"Winning ad to multiply. Alternative to `image_url`."},"image_url":{"type":"string","format":"uri","description":"Direct URL of the winning image. Alternative to `ad_id`."},"count":{"type":"integer","default":10,"maximum":20,"description":"How many variations to generate. Values above 20 are clamped to 20."},"aspect_ratio":{"type":"string","default":"1:1","description":"Output aspect ratio. AutoAdy generates `1:1`, `9:16` and `4:5`; the value is passed through without validation."},"request_id":{"type":"string","description":"Caller-generated idempotency key. Reuse it to retry safely; omit it and AutoAdy derives one from the request body, so an identical retry replays rather than writing twice."}}},"example":{"account_id":"act_1234567890","ad_id":"23851234567890123","count":6}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"207":{"$ref":"#/components/responses/PartialSuccess"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/competitor-creatives":{"post":{"operationId":"competitorCreatives","summary":"Generate creatives informed by a competitor","tags":["Tools"],"description":"Pulls a competitor's live ads from the public Meta Ad Library, reads what they are running, and generates on-brand creatives that answer it. Identify the competitor by name or by Meta page id.\n\nRuns directly against the account this API key can reach — the same execution path as the MCP server. **404** means no reachable Meta ad account (none connected, or the `account_id` you passed is not one this workspace can act on); **403** means the plan does not cover the tool or the key belongs to a read-only Client Viewer; **400** carries a tool-level failure under `data.error`.\n\nThis workflow writes to the ad account, so it is metered by the per-account write budget and is idempotent on the request body: retrying an identical body replays the first run's result instead of writing twice. To force a genuinely new run of the same input, pass a fresh `request_id`. A run the write boundary refused answers **409**.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["account_id"],"anyOf":[{"required":["competitor_name"]},{"required":["page_id"]}],"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Required for this tool.","examples":["act_1234567890"]},"competitor_name":{"type":"string","description":"Competitor brand name to search for."},"page_id":{"type":"string","description":"Competitor's Meta page id. More precise than a name."},"country":{"type":"string","default":"US","description":"Two-letter country code for the Ad Library search."},"request_id":{"type":"string","description":"Caller-generated idempotency key. Reuse it to retry safely; omit it and AutoAdy derives one from the request body, so an identical retry replays rather than writing twice."}}},"example":{"account_id":"act_1234567890","competitor_name":"Example Brand","country":"GB"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"207":{"$ref":"#/components/responses/PartialSuccess"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/creative-matrix":{"post":{"operationId":"creativeMatrix","summary":"Generate an angle × hook × style matrix","tags":["Tools"],"description":"Generates the cross-product of the angles, hooks and visual styles you pass, so a single call produces a structured test grid rather than a loose batch.\n\nThe grid is capped: `angles.length × hooks.length × visual_styles.length` must not exceed **27**, or the call is rejected with 400.\n\nRuns directly against the account this API key can reach — the same execution path as the MCP server. **404** means no reachable Meta ad account (none connected, or the `account_id` you passed is not one this workspace can act on); **403** means the plan does not cover the tool or the key belongs to a read-only Client Viewer; **400** carries a tool-level failure under `data.error`.\n\nThis workflow writes to the ad account, so it is metered by the per-account write budget and is idempotent on the request body: retrying an identical body replays the first run's result instead of writing twice. To force a genuinely new run of the same input, pass a fresh `request_id`. A run the write boundary refused answers **409**.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["account_id","angles"],"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Required for this tool.","examples":["act_1234567890"]},"angles":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Messaging angles. Required and non-empty."},"hooks":{"type":"array","items":{"type":"string"},"default":["question"],"description":"Hook styles to pair with each angle."},"visual_styles":{"type":"array","items":{"type":"string"},"default":["headline"],"description":"Visual treatments to pair with each angle/hook combination."},"aspect_ratio":{"type":"string","default":"1:1","description":"Output aspect ratio. AutoAdy generates `1:1`, `9:16` and `4:5`; the value is passed through without validation."},"request_id":{"type":"string","description":"Caller-generated idempotency key. Reuse it to retry safely; omit it and AutoAdy derives one from the request body, so an identical retry replays rather than writing twice."}}},"example":{"account_id":"act_1234567890","angles":["pain","gain","social_proof"],"hooks":["question","stat"],"visual_styles":["headline"]}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"207":{"$ref":"#/components/responses/PartialSuccess"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/creative-loop":{"post":{"operationId":"creativeLoop","summary":"Run the end-to-end creative refresh loop","tags":["Tools"],"description":"Finds fatiguing ads, generates replacements from what is winning, and stages them in the account. New creatives are created **PAUSED** unless `auto_launch` is `true`.\n\nRuns directly against the account this API key can reach — the same execution path as the MCP server. **404** means no reachable Meta ad account (none connected, or the `account_id` you passed is not one this workspace can act on); **403** means the plan does not cover the tool or the key belongs to a read-only Client Viewer; **400** carries a tool-level failure under `data.error`.\n\nThis workflow writes to the ad account, so it is metered by the per-account write budget and is idempotent on the request body: retrying an identical body replays the first run's result instead of writing twice. To force a genuinely new run of the same input, pass a fresh `request_id`. A run the write boundary refused answers **409**.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["account_id"],"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Required for this tool.","examples":["act_1234567890"]},"auto_launch":{"type":"boolean","default":false,"description":"When true, new creatives go live ACTIVE instead of being staged PAUSED."},"request_id":{"type":"string","description":"Caller-generated idempotency key. Reuse it to retry safely; omit it and AutoAdy derives one from the request body, so an identical retry replays rather than writing twice."}}},"example":{"account_id":"act_1234567890","auto_launch":false}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"207":{"$ref":"#/components/responses/PartialSuccess"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/emergency-recovery":{"post":{"operationId":"emergencyRecovery","summary":"Pause the ads bleeding the account","tags":["Tools"],"description":"Finds ads spending well above the account's average cost per result and pauses them. This is a real write, so it takes an idempotency key and is metered by the per-account write budget (200 writes per hour).\n\nA partially applied run answers **207**.\n\nRuns directly against the account this API key can reach — the same execution path as the MCP server. **404** means no reachable Meta ad account (none connected, or the `account_id` you passed is not one this workspace can act on); **403** means the plan does not cover the tool or the key belongs to a read-only Client Viewer; **400** carries a tool-level failure under `data.error`.\n\nThis workflow writes to the ad account, so it is metered by the per-account write budget and is idempotent on the request body: retrying an identical body replays the first run's result instead of writing twice. To force a genuinely new run of the same input, pass a fresh `request_id`. A run the write boundary refused answers **409**.\n\n**Plan: Pro or Agency.** A key on the Free plan gets HTTP 403 with an `upgrade_url`.\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["account_id","request_id"],"properties":{"account_id":{"type":"string","description":"Meta ad account id, e.g. `act_1234567890`. Required for this tool.","examples":["act_1234567890"]},"request_id":{"type":"string","description":"Caller-generated idempotency key. Reuse it to retry safely."},"threshold_cpl_multiplier":{"type":"number","default":2,"description":"Pause ads whose cost per result exceeds the account average by at least this factor."}}},"example":{"account_id":"act_1234567890","request_id":"recovery-2026-08-19-001","threshold_cpl_multiplier":2.5}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"207":{"$ref":"#/components/responses/PartialSuccess"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ForbiddenAccount"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/list-skills":{"post":{"operationId":"listSkills","summary":"List the published media-buying skills","tags":["Tools"],"description":"Returns every published AutoAdy skill with its slug, title and summary — the methodology the AI itself runs on. Use the slugs with `get-skill`. The request body is ignored; send `{}`.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{}},"example":{}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"type":"object","properties":{"skills":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Published skills, each with at least a `slug`."}},"additionalProperties":true}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/mcp/get-skill":{"post":{"operationId":"getSkill","summary":"Read one skill in full","tags":["Tools"],"description":"Returns the complete text of one published skill — the thresholds, decision rules and worked reasoning behind it. The `slug` is trimmed and lowercased before lookup.\n\nNote: a missing or unknown `slug` still answers **HTTP 200**, with `data.error` naming the valid slugs. Check `data.error` as well as the status.\n\n**Plan: available on every plan, including Free.**\n\nRate limit: 60 requests per minute per API key. A 429 carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` and `Retry-After` headers.","security":[{"ApiKeyBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["slug"],"properties":{"slug":{"type":"string","description":"Skill slug, as returned by `list-skills`.","examples":["audit","diagnose","scale"]}}},"example":{"slug":"audit"}}}},"responses":{"200":{"description":"Success. The result is under `data`.","content":{"application/json":{"schema":{"type":"object","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"description":"Tool result payload."}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}}},"components":{"securitySchemes":{"ApiKeyBearer":{"type":"http","scheme":"bearer","description":"An AutoAdy API key, sent as `Authorization: Bearer adk_...`. Create and revoke keys in the AutoAdy app under Settings → API Keys (maximum 3 active keys). Keys are stored as SHA-256 hashes — the plaintext is shown once, at creation. There is no query-parameter or cookie authentication for this API."}},"schemas":{"Envelope":{"type":"object","description":"The standard AutoAdy response wrapper. Both successful results and most errors are wrapped in it — read the HTTP status to tell them apart.","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)","description":"Attribution string. Always this exact value."},"data":{"description":"The tool result on 2xx, or an error object on a wrapped error status."}}},"WrappedError":{"type":"object","description":"A wrapped error: the same `{ source, data }` envelope, returned with a non-2xx status. `data.error` carries a human-readable message.","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable failure reason."}}}}},"BareError":{"type":"object","description":"An UNWRAPPED error body. Produced by 401 (key rejected before the wrapping layer runs) and 429 (emitted by the rate limiter). No `source` field is present.","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable failure reason."}}},"UpgradeRequired":{"type":"object","description":"Wrapped 403 telling a Free-plan key which page to upgrade on.","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"type":"object","required":["error","upgrade_url"],"properties":{"error":{"type":"string","examples":["Pro plan required. Upgrade at autoady.io/pricing"]},"upgrade_url":{"type":"string","format":"uri","examples":["https://www.autoady.io/pricing"]}}}}},"AccountNotAccessible":{"type":"object","description":"Wrapped error returned when the requested `account_id` is not one this workspace can act on. It is NOT an authentication failure — do not re-run OAuth. Pick an id from the `accounts` array, which mirrors what `list-accounts` returns.","required":["source","data"],"properties":{"source":{"type":"string","const":"AutoAdy — AI Meta Ads Optimization (autoady.io)"},"data":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"accounts":{"type":"array","description":"Accounts this API key can act on.","items":{"type":"object","additionalProperties":true}}}}}}},"responses":{"Unauthorized":{"description":"Missing, malformed, revoked, or expired API key — or the account is deactivated. Body is BARE (no `source` wrapper).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BareError"},"example":{"error":"Invalid or missing API key. Include: Authorization: Bearer adk_..."}}}},"BadRequest":{"description":"The request body failed validation. Wrapped error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WrappedError"}}}},"Forbidden":{"description":"The API key's plan does not include this tool. Wrapped error with an upgrade link.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeRequired"},"example":{"source":"AutoAdy — AI Meta Ads Optimization (autoady.io)","data":{"error":"Pro plan required. Upgrade at autoady.io/pricing","upgrade_url":"https://www.autoady.io/pricing"}}}}},"ForbiddenAccount":{"description":"Either the plan does not include this tool, or the requested `account_id` is not reachable by this workspace. Both are wrapped errors; the account case includes an `accounts` array.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/UpgradeRequired"},{"$ref":"#/components/schemas/AccountNotAccessible"}]}}}},"NotFound":{"description":"Unknown tool name, no connected Meta ad account, or an `account_id` this workspace cannot reach. Wrapped error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountNotAccessible"}}}},"Conflict":{"description":"The write was refused by the Meta write boundary — for example a duplicate `request_id`, a spent write budget, or a missing hard confirmation. Wrapped error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WrappedError"}}}},"BadGateway":{"description":"The upstream step failed or answered with something that was not JSON. Wrapped error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WrappedError"}}}},"PartialSuccess":{"description":"Partial success — some of the run's writes applied and some did not. The wrapped payload lists both outcomes under `data.partial`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Envelope"}}}},"TooManyRequests":{"description":"Over 60 requests per minute for this API key. Body is BARE (no `source` wrapper).","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window (60)."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Window reset, epoch milliseconds."},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait before retrying."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BareError"},"example":{"error":"Too many requests. Please try again later."}}}},"ServiceUnavailable":{"description":"AutoAdy's rate-limiting backend is degraded and the request was not attempted. Bare error body. Retry shortly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BareError"}}}}}}}