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 add pagination (limit, offset, has_more or a next_cursor).
  • Response fields are snake_case; request bodies use the same camelCase names as the dashboard and MCP tools (for example dailyBudgetUsd, platformCampaignId).
  • Writes propagate to the live ad platform (pause, resume, budgets, bids, targeting, keywords) and are recorded in your Activity Log with the API actor.
  • 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
GET/campaignsList campaigns
POST/campaignsCreate a draft campaign
GET/campaigns/{id}Get a campaign
PATCH/campaigns/{id}Update campaign name or end date
POST/campaigns/{id}/pausePause a campaign
POST/campaigns/{id}/resumeResume a campaign
POST/campaigns/{id}/budgetSet a campaign daily budget
POST/campaigns/{id}/automationToggle Tracking and Management on a campaign

AI campaign builds

scope: campaigns
POST/campaigns/buildStart an AI campaign buildAI plan
GET/campaigns/build/{taskId}Poll an AI campaign buildAI plan

Import live campaigns

scope: campaigns
GET/campaigns/importableList live campaigns you can import
POST/campaigns/importImport live campaigns into Lazy Ads

Ad sets and ads

scope: campaigns
POST/ad-sets/{id}/pausePause an ad set
POST/ad-sets/{id}/resumeResume an ad set
POST/ad-sets/{id}/budgetSet an ad set daily budget
POST/ad-sets/{id}/bidSet a manual ad-set bid (LinkedIn, TikTok, ChatGPT, Snapchat)
POST/ad-sets/{id}/targetingUpdate ad set targeting
POST/ad-sets/{id}/keywordsAdd search keywords
POST/ads/{id}/pausePause an ad
POST/ads/{id}/resumeResume an ad

Performance, creatives, and activity

scope: performance · creatives · campaigns
GET/performanceGet performance metrics
GET/creativesList creatives
GET/activityList user activity

Competitors

scope: competitors
GET/competitorsList tracked competitors
POST/competitorsAdd a competitor
GET/competitors/adsSearch competitor ads (Meta Ad Library)AI plan

Account, AI chat, and conversions

scope: connections · notifications · chat · performance
GET/connectionsList platform connections
POST/connectionsConnect ChatGPT
GET/notificationsList recent notifications
POST/chatChat with the LazyAds AI assistantAI plan
POST/eventsIngest first-party conversion events

Webhook subscriptions (REST Hooks)

scope: webhooks
GET/webhooksList webhook subscriptions
POST/webhooksSubscribe to webhook events (REST Hook)
DELETE/webhooksUnsubscribe by id or url
DELETE/webhooks/{id}Unsubscribe a webhook by id
GET/webhooks/eventsList webhook event types with sample payloads

Start 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, aiManaged lets the optimizer edit (both default per plan and stay off on BYOA).

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 } ] }'

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 key
PLAN_INSUFFICIENT403 — REST needs Growth+; AI endpoints need Starter+ AI access
PERMISSION_DENIED403 — the key was scoped and lacks this endpoint’s scope
CLIENT_ACCESS_DENIED / VIEWER_READ_ONLY403 — agency header without an active grant, or viewer attempted a write
RATE_LIMIT_EXCEEDED429 — wait for Retry-After seconds
INVALID_BODY / INVALID_INPUT400 — the first Zod issue is returned in message
NOT_FOUND404 — the resource is not owned by this account

Same actions from your agent

Every write above is also an MCP tool (for example pause_resume_campaign, set_ad_set_budget, import_platform_campaign, 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.