REST API reference
Base URL https://lazyads.ai/api/v1. Every request requires Authorization: Bearer <api_key> and a Growth, Scale, or Enterprise plan; BYOA and Starter keys use the MCP server instead. Download the machine-readable spec from openapi.json (OpenAPI 3.1, importable into Postman, Insomnia, or any generator).
curl https://lazyads.ai/api/v1/campaigns?status=active&limit=20 \
-H "Authorization: Bearer la_your_api_key"Conventions
- JSON in, JSON out. Successful responses wrap the payload in
data; list endpoints addpagination(limit,offset,has_moreor anext_cursor). - Response fields are
snake_case; request bodies use the samecamelCasenames as the dashboard and MCP tools (for exampledailyBudgetUsd,platformCampaignId). - Writes propagate to the live ad platform (pause, resume, budgets, bids, targeting, keywords, live copy, destination URL, Meta
url_tags, ad-set name, and end date) and are recorded in your Activity Log with theAPIactor. Published edits the platform cannot apply fail instead of silently changing only Lazy Ads. - Optional key scopes are listed per group below. Agencies pass
X-LazyAds-Client: <client user id>to act inside a client workspace; viewer members are read-only. - Rate limits: Growth 100, Scale 500, Enterprise 1000 requests per minute per key, with
X-RateLimit-*headers on every response.
Campaigns
scope:campaigns/campaignsList campaigns/campaignsCreate a draft campaign/campaigns/{id}Get a campaign/campaigns/{id}Update campaign name or end date/campaigns/{id}/pausePause a campaign/campaigns/{id}/resumeResume a campaign/campaigns/{id}/budgetSet a campaign daily budget/campaigns/{id}/automationToggle Tracking and Management on a campaignAI campaign builds
scope:campaigns/campaigns/buildStart an AI campaign buildAI plan/campaigns/build/{taskId}Poll an AI campaign buildAI planImport live campaigns
scope:campaigns/campaigns/importableList live campaigns you can import/campaigns/importImport live campaigns into Lazy AdsAd sets and ads
scope:campaigns/ad-sets/{id}Rename an ad set or set its end date/ad-sets/{id}/pausePause an ad set/ad-sets/{id}/resumeResume an ad set/ad-sets/{id}/budgetSet an ad set daily budget/ad-sets/{id}/bidSet a manual ad-set bid (LinkedIn, TikTok, ChatGPT, Snapchat)/ad-sets/{id}/targetingUpdate ad set targeting/ad-sets/{id}/keywordsAdd search keywords/ad-sets/{id}/optimization-eventSwitch the conversion event a Meta ad set optimizes for/ads/{id}Update ad copy, destination URL / UTMs, or attach a creative/ads/{id}/pausePause an ad/ads/{id}/resumeResume an adAccount signals: audiences and conversion events
scope:audiences/account-signalsAccount signals: pixels, conversion events, audiences, and the AI plan/audiencesList custom, lookalike, and retargeting audiences/audiencesCreate a first-party audience/conversion-eventsList pixel / tag conversion events with fire volumePerformance, creatives, and activity
scope:performance · creatives · campaigns/performanceGet performance metrics/creativesList creatives/activityList user activityCompetitors
scope:competitors/competitorsList tracked competitors/competitorsAdd a competitor/competitors/adsSearch competitor ads (Meta Ad Library)AI planAccount, AI chat, and conversions
scope:connections · notifications · chat · performance/connectionsList platform connections/connectionsConnect ChatGPT/notificationsList recent notifications/chatChat with the LazyAds AI assistantAI plan/eventsIngest first-party conversion eventsWebhook subscriptions (REST Hooks)
scope:webhooks/webhooksList webhook subscriptions/webhooksSubscribe to webhook events (REST Hook)/webhooksUnsubscribe by id or url/webhooks/{id}Unsubscribe a webhook by id/webhooks/eventsList webhook event types with sample payloadsStart and poll an AI campaign build
POST /campaigns/build accepts the same fields as the dashboard builder and MCP build_ai_campaign. Omit platforms to default to Meta. Poll GET /campaigns/build/{taskId} until status is completed or failed; the campaign lands in review (paused) on the platform.
curl -X POST https://lazyads.ai/api/v1/campaigns/build \
-H "Authorization: Bearer la_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"platforms": ["meta", "tiktok"],
"dailyBudgetUsd": 40,
"objectiveOverride": "OUTCOME_SALES",
"creativeMix": "existing",
"skipCompetitorAnalysis": false,
"confirmNotPolitical": true,
"preferredCreativeIds": ["cr_..."],
"customInstructions": "Avoid medical claims"
}'
# → 201 { "data": { "task_id": "...", "campaign_id": "...", "builds": [...] } }
curl "https://lazyads.ai/api/v1/campaigns/build/TASK_ID?campaignId=CAMPAIGN_ID" \
-H "Authorization: Bearer la_your_api_key"
# → { "data": { "status": "running", "output": { "steps": [...] } } }creativeMix is ai_decide (default), images_only, videos_only, images_and_videos, or existing (reuse the library, no new generation). Other optional fields: preferredPagePostId, socialContentIds, referenceCreativeIds. Live creative performance is on GET /creatives as lifetime_roas, lifetime_spend, and related fields.
Import campaigns you already run
List what is live on each connected account, then link the ones you want. A worker pulls structure and daily stats; trackingEnabled feeds the dashboard and AI analysis, and aiManaged (Management) lets the optimizer edit budgets, bids, and ads. Tracking defaults on for Starter and above and stays off on Free and BYOA. Management is off on every plan when you import, until you turn it on for a campaign (send aiManaged: true or call POST /campaigns/{id}/automation; Starter and above).
curl "https://lazyads.ai/api/v1/campaigns/importable?platform=google,meta" \
-H "Authorization: Bearer la_your_api_key"
curl -X POST https://lazyads.ai/api/v1/campaigns/import \
-H "Authorization: Bearer la_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "campaigns": [ { "platform": "google", "platformCampaignId": "123456", "trackingEnabled": true } ] }'Edit a live ad or ad set
PATCH /ads/{id} edits live copy, destination URL, and Meta url_tags / UTMs where supported. Optional fields: name, headline, body, description, callToAction, destinationUrl, urlTags, and creativeId (library attach; a live creative swap only works when a platform creative id already exists). Same action from MCP: update_ad.
PATCH /ad-sets/{id} renames an ad set or sets its end date where supported (name on Meta, TikTok, LinkedIn, Snapchat, and ChatGPT; end date on Meta and TikTok). Send name and/or endDate as YYYY-MM-DD. Same action from MCP: update_ad_set.
Both write Lazy Ads and the live platform when that API supports the field. Published entities fail instead of a silent DB-only write. Check appliedOnPlatform on success; unsupported published edits return 400.
curl -X PATCH https://lazyads.ai/api/v1/ads/AD_ID \
-H "Authorization: Bearer la_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"headline": "Fresh headline",
"destinationUrl": "https://example.com/offer",
"urlTags": "utm_source=meta&utm_medium=paid&utm_campaign=spring"
}'
# → { "data": { "appliedOnPlatform": true, ... }, "message": "Ad updated on the live platform." }
curl -X PATCH https://lazyads.ai/api/v1/ad-sets/ADSET_ID \
-H "Authorization: Bearer la_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Retargeting · week 2", "endDate": "2026-10-31" }'
# → { "data": { "appliedOnPlatform": true, ... } }Read and shape account signals
GET /account-signals returns what the AI sees before it builds or optimizes: pixels and tags with fire volume, every conversion event with 7-day and 30-day counts, custom / lookalike / retargeting audiences with sizes, and the plan derived from them (the event to optimize for now, the event to graduate to once volume clears the learning threshold, exclusion and warm-audience ids, and audiences worth creating). GET /audiences and GET /conversion-events return the same data split by concern. POST /audiences creates a first-party audience where the platform API allows it (Meta, TikTok, Snapchat, Google); an equivalent existing audience is returned instead of a duplicate. POST /ad-sets/{id}/optimization-event switches a live Meta ad set to a different pixel event or custom conversion.
curl "https://lazyads.ai/api/v1/account-signals?platform=meta" \
-H "Authorization: Bearer la_your_api_key"
# → { "data": { "pixels": [...], "conversionEvents": [{ "eventName": "Purchase", "count7d": 42, ... }],
# "audiences": [...], "eventPlan": { "primary": {...}, "graduateTo": {...} }, "audiencePlan": {...} } }
curl -X POST https://lazyads.ai/api/v1/audiences \
-H "Authorization: Bearer la_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "platform": "meta", "kind": "lookalike", "seedAudienceId": "23851234567890123", "lookalikeRatio": 0.01 }'
# → 201 { "data": { "created": true, "audience": { "id": "...", "name": "LazyAds · Lookalike 1% ..." } } }
curl -X POST https://lazyads.ai/api/v1/ad-sets/ADSET_ID/optimization-event \
-H "Authorization: Bearer la_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "customEventType": "PURCHASE", "reason": "Purchases cleared 50/week" }'
# → { "data": { "optimizationEvent": {...}, "warnings": [] } }Send server-side conversions
POST /events takes a batch of up to 100 events. Reuse the browser pixel's eventId so Meta CAPI deduplicates; set googleConversionActionId to also forward Google Enhanced Conversions. User fields are hashed before forwarding.
curl -X POST https://lazyads.ai/api/v1/events \
-H "Authorization: Bearer la_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"events": [{
"eventName": "Purchase",
"eventId": "order_8841",
"value": 129.00,
"currency": "USD",
"orderId": "8841",
"fbclid": "IwAR...",
"user": { "email": "buyer@example.com" }
}]
}'Errors
Errors return a JSON body with a stable code and the HTTP status:
{
"error": {
"message": "The REST API requires the Growth plan or above. Your API key still works with the Lazy Ads MCP server at https://mcp.lazyads.ai/mcp.",
"code": "PLAN_INSUFFICIENT",
"status": 403
}
}MISSING_AUTH / INVALID_AUTH_FORMAT / INVALID_KEY401 — send Authorization: Bearer la_… with an active keyPLAN_INSUFFICIENT403 — REST needs Growth+; AI endpoints need Starter+ AI accessPERMISSION_DENIED403 — the key was scoped and lacks this endpoint’s scopeCLIENT_ACCESS_DENIED / VIEWER_READ_ONLY403 — agency header without an active grant, or viewer attempted a writeRATE_LIMIT_EXCEEDED429 — wait for Retry-After secondsINVALID_BODY / INVALID_INPUT400 — the first Zod issue is returned in messageNOT_FOUND404 — the resource is not owned by this accountSame actions from your agent
Every write above is also an MCP tool (for example pause_resume_campaign, update_ad, update_ad_set, set_ad_set_budget, import_platform_campaign, create_audience, build_ai_campaign). If your automation lives in Claude, Cursor, Codex, or Hermes, the MCP server is the shorter path and works on every paid plan.