API Reference · v1

Snap Campaigns API

Research, launch, measure, and optimize ad campaigns programmatically.

Getting started

Four steps from zero to your first metrics pull. All requests go to https://snapcampaigns.com.

  1. 1

    Create an API key

    Open the developer settings in your dashboard and create a key. Test-mode keys start with sc_test_, live keys with sc_live_. The full key is shown once — store it securely. Open developer settings →

  2. 2

    List your campaigns

    Pass the key as a Bearer token. Every v1 endpoint uses the same header.

    curl https://snapcampaigns.com/api/v1/campaigns \
      -H "Authorization: Bearer sc_test_…"
  3. 3

    Generate a research report

    Kick off audience and competitor research for a campaign. Add up to five competitors to pull their active ads.

    curl https://snapcampaigns.com/api/v1/research-reports \
      -X POST \
      -H "Authorization: Bearer sc_test_…" \
      -H "Content-Type: application/json" \
      -d '{
        "campaign_id": "cmp_4e21ab90c7d3",
        "competitors": [{ "name": "TrailPeak Gear", "domain": "trailpeak.com" }]
      }'
  4. 4

    Fetch performance metrics

    Pull time-windowed totals, KPIs, per-platform splits, daily series, and breakdowns.

    curl "https://snapcampaigns.com/api/v1/campaigns/cmp_4e21ab90c7d3/metrics?window=30" \
      -H "Authorization: Bearer sc_test_…"

Authentication

Every request must include an API key as a Bearer token. Keys come in two modes: sc_test_… for test mode and sc_live_… for live mode.

Authorization: Bearer sc_test_3f9a1c2d4e5b6a7f8090a1b2c3d4e5f60718293a

Each key carries scopes that gate what it can do. Calling an endpoint the key is not scoped for returns 403 insufficient_scope.

research:readresearch:writecampaigns:readcampaigns:writemetrics:readrecommendations:read

The full key is shown exactly once at creation — only a hash is stored. Revoked keys fail with 401 unauthorized.

Rate limits

Requests are limited per key, per minute, across all endpoints. When you exceed your limit the API responds with 429 and a rate_limited error envelope, plus these headers:

  • Retry-After: 60 — seconds until the next minute window.
  • X-RateLimit-Limit — your key’s requests-per-minute limit.
  • X-RateLimit-Remaining — requests left in the current window (0 when limited).
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0

{ "error": { "code": "rate_limited", "message": "Rate limit of 120 requests/minute exceeded." } }

Research Reports

Audience & competitor research reports with shareable web and PDF views.

get/api/v1/research-reports

List research reports

Returns up to 50 of the workspace’s research reports, newest first. Requires the `research:read` scope.

Parameters

NameInTypeRequiredDescription
campaign_idquerystringNoOnly return reports for this campaign.

Example response

{
  "object": "list",
  "data": [
    {
      "id": "rpt_8f3a1c2d4e5b",
      "object": "research_report",
      "campaignId": "cmp_4e21ab90c7d3",
      "title": "Acme Outdoor — Audience & Competitor Research",
      "status": "ready",
      "shareUrl": "https://snapcampaigns.com/reports/shr_p2x9k4m1",
      "pdfUrl": "https://snapcampaigns.com/reports/shr_p2x9k4m1/pdf",
      "generatedAt": "2026-06-01T18:24:09.000Z",
      "createdAt": "2026-06-01T18:22:41.000Z"
    }
  ]
}
post/api/v1/research-reports

Generate a research report

Generates an audience & competitor research report for a campaign. Up to 5 competitors can be analyzed. Requires the `research:write` scope.

Request body

{
  "campaign_id": "cmp_4e21ab90c7d3",
  "competitors": [
    {
      "name": "TrailPeak Gear",
      "domain": "trailpeak.com"
    }
  ]
}

Example response

{
  "id": "rpt_8f3a1c2d4e5b",
  "object": "research_report",
  "campaignId": "cmp_4e21ab90c7d3",
  "title": "Acme Outdoor — Audience & Competitor Research",
  "status": "ready",
  "shareUrl": "https://snapcampaigns.com/reports/shr_p2x9k4m1",
  "pdfUrl": "https://snapcampaigns.com/reports/shr_p2x9k4m1/pdf",
  "generatedAt": "2026-06-01T18:24:09.000Z",
  "createdAt": "2026-06-01T18:22:41.000Z"
}
get/api/v1/research-reports/{id}

Retrieve a research report

Returns one report including its full `content` and `competitorIntel`. Requires the `research:read` scope.

Parameters

NameInTypeRequiredDescription
idpathstringYesResearch report ID.

Example response

{
  "id": "rpt_8f3a1c2d4e5b",
  "object": "research_report",
  "campaignId": "cmp_4e21ab90c7d3",
  "title": "Acme Outdoor — Audience & Competitor Research",
  "status": "ready",
  "shareUrl": "https://snapcampaigns.com/reports/shr_p2x9k4m1",
  "pdfUrl": "https://snapcampaigns.com/reports/shr_p2x9k4m1/pdf",
  "generatedAt": "2026-06-01T18:24:09.000Z",
  "createdAt": "2026-06-01T18:22:41.000Z",
  "content": {
    "summary": "Acme Outdoor’s buyers skew 28–45, research-heavy, and respond to durability proof points.",
    "personas": [
      {
        "name": "Weekend Basecamper",
        "painPoints": [
          "gear that fails in rain"
        ]
      }
    ]
  },
  "competitorIntel": {
    "competitors": [
      {
        "name": "TrailPeak Gear",
        "activeAds": 14,
        "topAngle": "lifetime warranty"
      }
    ]
  }
}

Campaigns

List campaigns, inspect launch state, generate channel plans, and launch.

get/api/v1/campaigns

List campaigns

Returns up to 50 of the workspace’s campaigns with launch state and channel plan, most recently updated first. Requires the `campaigns:read` scope.

Example response

{
  "object": "list",
  "data": [
    {
      "id": "cmp_4e21ab90c7d3",
      "object": "campaign",
      "name": "Acme Outdoor",
      "status": "launched",
      "objective": "leads",
      "focus": "Spring tent sale",
      "channels": {
        "meta": "120218890123456789",
        "google": "22765432109",
        "linkedin": null
      },
      "channelPlan": {
        "totalDailyBudgetUsd": 150,
        "generatedAt": "2026-06-02T09:11:30.000Z",
        "channels": [
          {
            "channel": "meta",
            "budgetSharePct": 55,
            "dailyBudgetUsd": 82.5,
            "rationale": "Primary prospecting channel: scale, interest targeting, and fast creative iteration.",
            "formats": [
              "single_image",
              "carousel"
            ],
            "status": "planned"
          },
          {
            "channel": "google",
            "budgetSharePct": 30,
            "dailyBudgetUsd": 45,
            "rationale": "High-intent search capture converts demand the social channels create.",
            "formats": [
              "responsive_search_ad"
            ],
            "status": "planned"
          },
          {
            "channel": "linkedin",
            "budgetSharePct": 15,
            "dailyBudgetUsd": 22.5,
            "rationale": "Secondary reach for professional segments identified in research.",
            "formats": [
              "single_image",
              "carousel",
              "text_ad"
            ],
            "status": "planned"
          }
        ]
      },
      "createdAt": "2026-05-28T16:02:12.000Z",
      "updatedAt": "2026-06-08T07:45:51.000Z"
    }
  ]
}
get/api/v1/campaigns/{id}

Retrieve a campaign

Campaign detail including per-channel launch IDs, the stored channel plan, and metrics sync status. Requires the `campaigns:read` scope.

Parameters

NameInTypeRequiredDescription
idpathstringYesCampaign ID.

Example response

{
  "id": "cmp_4e21ab90c7d3",
  "object": "campaign",
  "name": "Acme Outdoor",
  "status": "launched",
  "objective": "leads",
  "focus": "Spring tent sale",
  "channels": {
    "meta": "120218890123456789",
    "google": "22765432109",
    "linkedin": null
  },
  "channelPlan": {
    "totalDailyBudgetUsd": 150,
    "generatedAt": "2026-06-02T09:11:30.000Z",
    "channels": [
      {
        "channel": "meta",
        "budgetSharePct": 55,
        "dailyBudgetUsd": 82.5,
        "rationale": "Primary prospecting channel: scale, interest targeting, and fast creative iteration.",
        "formats": [
          "single_image",
          "carousel"
        ],
        "status": "planned"
      },
      {
        "channel": "google",
        "budgetSharePct": 30,
        "dailyBudgetUsd": 45,
        "rationale": "High-intent search capture converts demand the social channels create.",
        "formats": [
          "responsive_search_ad"
        ],
        "status": "planned"
      },
      {
        "channel": "linkedin",
        "budgetSharePct": 15,
        "dailyBudgetUsd": 22.5,
        "rationale": "Secondary reach for professional segments identified in research.",
        "formats": [
          "single_image",
          "carousel",
          "text_ad"
        ],
        "status": "planned"
      }
    ]
  },
  "createdAt": "2026-05-28T16:02:12.000Z",
  "updatedAt": "2026-06-08T07:45:51.000Z",
  "metricsSync": [
    {
      "platform": "meta",
      "status": "success",
      "lastError": null,
      "finishedAt": "2026-06-08T07:45:51.000Z",
      "nextRetryAt": null
    }
  ]
}
post/api/v1/campaigns/{id}/plan

Generate a channel plan

Generates (or regenerates) the multi-channel budget plan for a campaign. Budget is clamped to $10–$100,000/day; unknown channels are ignored. Requires the `campaigns:write` scope.

Parameters

NameInTypeRequiredDescription
idpathstringYesCampaign ID.

Request body

{
  "total_daily_budget_usd": 150,
  "channels": [
    "meta",
    "google",
    "linkedin"
  ]
}

Example response

{
  "object": "channel_plan",
  "campaignId": "cmp_4e21ab90c7d3",
  "totalDailyBudgetUsd": 150,
  "generatedAt": "2026-06-02T09:11:30.000Z",
  "channels": [
    {
      "channel": "meta",
      "budgetSharePct": 55,
      "dailyBudgetUsd": 82.5,
      "rationale": "Primary prospecting channel: scale, interest targeting, and fast creative iteration.",
      "formats": [
        "single_image",
        "carousel"
      ],
      "status": "planned"
    },
    {
      "channel": "google",
      "budgetSharePct": 30,
      "dailyBudgetUsd": 45,
      "rationale": "High-intent search capture converts demand the social channels create.",
      "formats": [
        "responsive_search_ad"
      ],
      "status": "planned"
    },
    {
      "channel": "linkedin",
      "budgetSharePct": 15,
      "dailyBudgetUsd": 22.5,
      "rationale": "Secondary reach for professional segments identified in research.",
      "formats": [
        "single_image",
        "carousel",
        "text_ad"
      ],
      "status": "planned"
    }
  ]
}
post/api/v1/campaigns/{id}/launch

Launch a campaign

Unified launch across the planned channels (or an explicit subset). Channels already live report `already_launched`; channels missing an ad-platform connection report `needs_setup`. Requires the `campaigns:write` scope.

Parameters

NameInTypeRequiredDescription
idpathstringYesCampaign ID.

Request body

{
  "channels": [
    "meta",
    "google"
  ]
}

Example response

{
  "object": "launch_result",
  "campaignId": "cmp_4e21ab90c7d3",
  "results": [
    {
      "channel": "meta",
      "status": "launched",
      "campaignId": "120218890123456789",
      "detail": "Campaign created and activated."
    },
    {
      "channel": "google",
      "status": "needs_setup",
      "detail": "Connect Google Ads in the dashboard to launch this channel."
    }
  ],
  "channelPlan": {
    "totalDailyBudgetUsd": 150,
    "generatedAt": "2026-06-02T09:11:30.000Z",
    "channels": [
      {
        "channel": "meta",
        "budgetSharePct": 55,
        "dailyBudgetUsd": 82.5,
        "rationale": "Primary prospecting channel: scale, interest targeting, and fast creative iteration.",
        "formats": [
          "single_image",
          "carousel"
        ],
        "status": "planned"
      },
      {
        "channel": "google",
        "budgetSharePct": 30,
        "dailyBudgetUsd": 45,
        "rationale": "High-intent search capture converts demand the social channels create.",
        "formats": [
          "responsive_search_ad"
        ],
        "status": "planned"
      },
      {
        "channel": "linkedin",
        "budgetSharePct": 15,
        "dailyBudgetUsd": 22.5,
        "rationale": "Secondary reach for professional segments identified in research.",
        "formats": [
          "single_image",
          "carousel",
          "text_ad"
        ],
        "status": "planned"
      }
    ]
  }
}

Metrics

Time-windowed performance metrics: totals, KPIs, per-platform splits, daily series, breakdowns.

get/api/v1/campaigns/{id}/metrics

Retrieve campaign metrics

Time-windowed performance: totals with derived KPIs, per-platform split, daily series, and ad set / ad / audience breakdowns. Requires the `metrics:read` scope.

Parameters

NameInTypeRequiredDescription
idpathstringYesCampaign ID.
windowqueryintegerNoLookback window in days (1–180).

Example response

{
  "object": "campaign_metrics",
  "campaignId": "cmp_4e21ab90c7d3",
  "windowDays": 30,
  "totals": {
    "impressions": 184220,
    "clicks": 3911,
    "spend": 1873.4,
    "conversions": 162,
    "conversionsValue": 9612.75,
    "reach": 121408,
    "ctr": 2.123,
    "cpc": 0.48,
    "cpm": 10.17,
    "cpa": 11.56,
    "roas": 5.13
  },
  "byPlatform": {
    "meta": {
      "impressions": 184220,
      "clicks": 3911,
      "spend": 1873.4,
      "conversions": 162,
      "conversionsValue": 9612.75,
      "reach": 121408,
      "ctr": 2.123,
      "cpc": 0.48,
      "cpm": 10.17,
      "cpa": 11.56,
      "roas": 5.13
    }
  },
  "daily": [
    {
      "date": "2026-06-07",
      "platform": "meta",
      "impressions": 6140,
      "clicks": 131,
      "spend": 62.18,
      "conversions": 6,
      "conversionsValue": 348.5
    }
  ],
  "breakdowns": {
    "adsets": [
      {
        "platform": "meta",
        "level": "adset",
        "entityId": "238410000123",
        "entityName": "Prospecting — Hiking interests",
        "audienceKey": "hiking_interests",
        "totals": {
          "impressions": 184220,
          "clicks": 3911,
          "spend": 1873.4,
          "conversions": 162,
          "conversionsValue": 9612.75,
          "reach": 121408,
          "ctr": 2.123,
          "cpc": 0.48,
          "cpm": 10.17,
          "cpa": 11.56,
          "roas": 5.13
        }
      }
    ],
    "ads": [],
    "audiences": [
      {
        "audienceKey": "hiking_interests",
        "totals": {
          "impressions": 184220,
          "clicks": 3911,
          "spend": 1873.4,
          "conversions": 162,
          "conversionsValue": 9612.75,
          "reach": 121408,
          "ctr": 2.123,
          "cpc": 0.48,
          "cpm": 10.17,
          "cpa": 11.56,
          "roas": 5.13
        }
      }
    ]
  }
}

Recommendations

Ranked optimization recommendations generated from the latest performance data.

get/api/v1/campaigns/{id}/recommendations

List open recommendations

Returns up to 25 open recommendations for the campaign, ranked by predicted impact (rank 1 first). Requires the `recommendations:read` scope.

Parameters

NameInTypeRequiredDescription
idpathstringYesCampaign ID.

Example response

{
  "object": "list",
  "data": [
    {
      "id": "rec_1d9e7b3a5c2f",
      "object": "recommendation",
      "campaignId": "cmp_4e21ab90c7d3",
      "kind": "budget_shift",
      "title": "Shift $20/day from Google to Meta",
      "rationale": "Meta CPA ($9.80) is 41% lower than Google ($16.60) over the last 14 days at comparable volume.",
      "predictedImpact": "+12 conversions/month at flat spend",
      "rank": 1,
      "status": "open",
      "source": "performance_analysis",
      "dataThrough": "2026-06-08T00:00:00.000Z",
      "createdAt": "2026-06-08T07:50:02.000Z"
    }
  ]
}
post/api/v1/campaigns/{id}/recommendations

Regenerate recommendations

Re-runs recommendation generation from the latest synced performance data and returns how many were created. Requires the `recommendations:read` scope.

Parameters

NameInTypeRequiredDescription
idpathstringYesCampaign ID.

Example response

{
  "object": "regeneration_result",
  "campaignId": "cmp_4e21ab90c7d3",
  "created": 4
}

Webhooks

Subscribe HTTPS endpoints to events from your dashboard. Failed deliveries are retried with exponential backoff for up to 6 attempts.

Event types

  • campaign.launchedA campaign finished launching on one or more ad channels.
  • metrics.updatedFresh performance metrics were synced for a campaign.
  • recommendation.createdA new optimization recommendation was generated.
  • autopilot.action_executedAutopilot executed an optimization action on your behalf.

Payload

Events are delivered as JSON POSTs with the envelope { id, type, createdAt, data } and an X-SnapCampaigns-Event header.

{
  "id": "whd_5e8b2c91a4f7",
  "type": "campaign.launched",
  "createdAt": "2026-06-08T07:45:51.000Z",
  "data": {
    "campaignId": "cmp_4e21ab90c7d3",
    "results": [{ "channel": "meta", "status": "launched", "campaignId": "120218890123456789" }]
  }
}

Verifying signatures

Each delivery is signed with your endpoint’s secret (shown once at creation). The X-SnapCampaigns-Signature header has the form t=<unix>,v1=<signature>, where v1 is the hex HMAC-SHA256 of `${t}.${body}` using your signing secret. Verify with a timing-safe compare:

Node.js

const crypto = require('node:crypto')

// X-SnapCampaigns-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256>
function verifySnapCampaignsSignature(secret, signatureHeader, rawBody) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((pair) => pair.split('=')),
  )
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex')
  return crypto.timingSafeEqual(
    Buffer.from(parts.v1, 'hex'),
    Buffer.from(expected, 'hex'),
  )
}

Errors

All errors share a single JSON envelope:

{
  "error": {
    "code": "insufficient_scope",
    "message": "This key is missing the required scope \"campaigns:write\"."
  }
}
CodeHTTP statusMeaning
unauthorized401Missing, malformed, or revoked API key.
insufficient_scope403The key lacks the scope this endpoint requires.
rate_limited429Per-key per-minute rate limit exceeded — retry after Retry-After seconds.
not_found404No matching resource exists in your workspace.
invalid_request400The request body or parameters failed validation.
internal_error500Something went wrong on our side — safe to retry.

OpenAPI

The full machine-readable OpenAPI 3.1 specification — everything on this page is generated from it. Feed it to your codegen tool, Postman, or an LLM.

curl https://snapcampaigns.com/api/v1/openapi
Download the OpenAPI spec ↓