Atribu
API Reference

Campaigns

Campaign performance, ROAS, ad-level breakdowns, and daily spend trends.

Top Campaigns

Endpoint
GET /api/v1/campaigns

Returns top-performing campaigns ranked by attributed outcome value, with ROAS and spend data. Pass level to drill down to ad sets or individual ads.

Scope: campaigns:read

Parameters

ParameterTypeRequiredDescription
date_fromstringYesStart date in YYYY-MM-DD format.
date_tostringYesEnd date in YYYY-MM-DD format.
modelstringNoAttribution model. Default last_touch. Options: first_touch, linear, time_decay, last_non_direct.
limitnumberNoMaximum results. Default 10, max 100.
levelstringNoHierarchy level: campaign, ad_set, or ad. When set, returns detailed performance fields.

Request

cURL
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
  "https://www.atribu.app/api/v1/campaigns?date_from=2026-03-01&date_to=2026-03-25&model=last_touch&limit=5"
JavaScript
const res = await fetch(
  "https://www.atribu.app/api/v1/campaigns?date_from=2026-03-01&date_to=2026-03-25&model=last_touch&limit=5",
  { headers: { Authorization: "Bearer atb_live_YOUR_KEY" } }
);
const { data, meta } = await res.json();
Python
import requests

res = requests.get(
    "https://www.atribu.app/api/v1/campaigns",
    headers={"Authorization": "Bearer atb_live_YOUR_KEY"},
    params={
        "date_from": "2026-03-01",
        "date_to": "2026-03-25",
        "model": "last_touch",
        "limit": 5,
    },
)
data = res.json()["data"]

Response

Success response (200 OK)
{
  "data": [
    {
      "campaign_id": "uuid",
      "campaign_name": "Spring Sale - Conversions",
      "spend": 1800.00,
      "outcome_count": 45,
      "outcome_value": 6200.00,
      "roas": 3.44
    }
  ],
  "meta": {
    "date_from": "2026-03-01",
    "date_to": "2026-03-25",
    "profile_id": "uuid"
  }
}

Response fields

FieldTypeDescription
campaign_idstringInternal campaign UUID.
campaign_namestringHuman-readable campaign name from the ad platform.
spendnumberTotal ad spend in your reporting currency.
outcome_countnumberNumber of attributed conversions.
outcome_valuenumberTotal attributed cash revenue.
roasnumberReturn on ad spend (outcome_value / spend).

Ad-level detail

Pass level=ad to get granular performance per ad creative. This adds additional fields to each row.

cURL — ad-level breakdown
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
  "https://www.atribu.app/api/v1/campaigns?date_from=2026-03-01&date_to=2026-03-25&level=ad"
JavaScript — ad-level breakdown
const res = await fetch(
  "https://www.atribu.app/api/v1/campaigns?date_from=2026-03-01&date_to=2026-03-25&level=ad",
  { headers: { Authorization: "Bearer atb_live_YOUR_KEY" } }
);
const { data } = await res.json();
Python — ad-level breakdown
res = requests.get(
    "https://www.atribu.app/api/v1/campaigns",
    headers={"Authorization": "Bearer atb_live_YOUR_KEY"},
    params={"date_from": "2026-03-01", "date_to": "2026-03-25", "level": "ad"},
)
data = res.json()["data"]

Additional fields when level is set

FieldTypeDescription
entity_levelstringThe level of this row (campaign, ad_set, ad).
parent_namestringName of the parent entity (campaign or ad set).
impressionsnumberTotal impressions served.
clicksnumberTotal clicks.
reachnumberUnique accounts reached.
ctrnumberClick-through rate (%).
avg_cpmnumberAverage cost per 1,000 impressions.
avg_cpcnumberAverage cost per click.
cacnumberCustomer acquisition cost (spend / outcome_count).
statusstringEntity status (ACTIVE, PAUSED, etc.).
objectivestringCampaign objective.
daily_budgetnumberDaily budget if set on the platform.

Campaign Trend

Endpoint
GET /api/v1/campaigns/trend

Returns daily spend, impressions, and clicks for up to 10 specific campaigns, ad sets, or ads. Use this to render sparklines or compare entity performance over time.

Scope: campaigns:read

Parameters

ParameterTypeRequiredDescription
date_fromstringYesStart date in YYYY-MM-DD format.
date_tostringYesEnd date in YYYY-MM-DD format.
entity_idsstringYesComma-separated list of entity UUIDs (max 10).
levelstringNocampaign, ad_set, or ad. Default campaign.

Request

cURL
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
  "https://www.atribu.app/api/v1/campaigns/trend?date_from=2026-03-20&date_to=2026-03-25&entity_ids=uuid1,uuid2&level=campaign"
JavaScript
const ids = ["uuid1", "uuid2"].join(",");
const res = await fetch(
  `https://www.atribu.app/api/v1/campaigns/trend?date_from=2026-03-20&date_to=2026-03-25&entity_ids=${ids}&level=campaign`,
  { headers: { Authorization: "Bearer atb_live_YOUR_KEY" } }
);
const { data } = await res.json();
Python
import requests

res = requests.get(
    "https://www.atribu.app/api/v1/campaigns/trend",
    headers={"Authorization": "Bearer atb_live_YOUR_KEY"},
    params={
        "date_from": "2026-03-20",
        "date_to": "2026-03-25",
        "entity_ids": "uuid1,uuid2",
        "level": "campaign",
    },
)
data = res.json()["data"]

Response

Success response (200 OK)
{
  "data": [
    { "entity_id": "uuid1", "date": "2026-03-20", "spend": 120.00, "impressions": 15000, "clicks": 340 },
    { "entity_id": "uuid1", "date": "2026-03-21", "spend": 135.00, "impressions": 16200, "clicks": 380 },
    { "entity_id": "uuid2", "date": "2026-03-20", "spend": 95.00, "impressions": 11800, "clicks": 275 }
  ],
  "meta": {
    "date_from": "2026-03-20",
    "date_to": "2026-03-25",
    "profile_id": "uuid"
  }
}

Response fields

FieldTypeDescription
entity_idstringThe campaign, ad set, or ad UUID.
datestringCalendar date (YYYY-MM-DD).
spendnumberAd spend for that entity on that day.
impressionsnumberImpressions served.
clicksnumberClicks recorded.

Entity ID format

entity_ids expects Atribu internal UUIDs (from the campaign_id field in the Top Campaigns response), not platform-specific IDs. You can pass up to 10 IDs in a single request.


Top Performers

Endpoint
GET /api/v1/top-performers

The profile's best-performing ads, scored against comparable creative — a cohort = channel × format × objective × audience warmth × geo × placement. The score is cohort-normalized, empirical-Bayes-smoothed (a small-sample ad shrinks toward the cohort mean — it lands mid-pack, the honest "we don't know yet"), and maturity-staged. So a $500/mo clinic and a $30k/mo clinic are ranked apples-to-apples.

Each ad carries three distinct measures — never merge them:

  • composite_score (0–100) — a transparent rule-based blend of the ad's within-cohort percentiles across funnel layers. The headline rank.
  • top_performer_likelihood (0–1) — a probability: a likelihood, not a guarantee. When score_source is model it's the calibrated output of a LambdaMART creative ranker (model_version tells you which model); otherwise (score_source is rules) it's a monotone function of composite_score. It is not ROAS and not lift.
  • attributed_revenue / roas (and attributed_outcomes_total / attributed_pipeline_outcomes / attributed_pipeline_value) — real Atribu-attributed outcomes. truth_grade='attributed' means Atribu deterministically attributed ≥1 outcome of any kind to this ad (cash payments or pipeline conversions — leads, appointments, closed-won). meta_reported_conversions / meta_reported_conversion_value are a separate, lower-confidence signal — Meta's own last-click count for the ad, not Atribu's chain; they never set truth_grade.

primary_outcome_kind ∈ cash · pipeline · messaging · meta · none tells you which of the above to headline for a given ad (a lead-gen ad shows pipeline outcomes, a Messages ad shows conversations started, an ad with only Meta-reported conversions shows meta_reported_conversions labeled as Meta's attribution, none = no attributed outcome yet → use composite_score).

maturity_stage (cold → early → mature → calibrated) says how settled the score is — act on mature/calibrated, treat cold as provisional. reason_codes explain why an ad ranks (which funnel layer is strong or weak, each with a sample_confidence band). Scores refresh on a daily cadence.

Scope: campaigns:read

Parameters

ParameterTypeRequiredDescription
windowstringNoRolling lookback: 7d, 14d, 28d (default), or lifetime. Not a custom date range.
limitnumberNoMaximum ads. Default 10, max 50.
min_spendnumberNoOnly ads with at least this much spend in the window.
objectivesstringNoComma-separated cohort objectives to keep (messaging, sales, leads, traffic, awareness).
truth_gradesstringNoComma-separated: predicted, attributed, lift.
outcome_kindsstringNoComma-separated headline-outcome kinds to keep: cash, pipeline, messaging, meta, none.
formatsstringNoComma-separated creative formats (ugc_video, talking_head, static, carousel, …).
has_videobooleanNotrue to keep only ads with a video creative; false for only static.

Request

cURL
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
  "https://www.atribu.app/api/v1/top-performers?window=28d&limit=5&truth_grades=attributed"

Response

Success response (200 OK)
{
  "data": [
    {
      "ad_external_id": "120210000000000123",
      "ad_name": "UGC — before/after — DM offer",
      "campaign_name": "Always-on — Messaging",
      "ad_set_name": "Prospecting — broad",
      "creative_thumbnail_url": "https://…",
      "video_id": "987654321",
      "score_window": "28d",
      "composite_score": 78,
      "top_performer_likelihood": 0.81,
      "model_version": 3,
      "score_source": "model",
      "maturity_stage": "mature",
      "truth_grade": "attributed",
      "primary_outcome_kind": "messaging",
      "cohort_key": "meta|ugc_video|messaging|prospecting|geo_any|advantage",
      "cohort_objective": "messaging",
      "cohort_format": "ugc_video",
      "cohort_audience_warmth": "prospecting",
      "cohort_n_ads": 17,
      "hook_type": "before_after",
      "creative_format": "ugc_video",
      "cta_type": "send_dm",
      "primary_angle": "fast visible results",
      "offers": ["free consultation"],
      "spend": 4120.0,
      "impressions": 512000,
      "ctr": 1.42,
      "cpc": 0.57,
      "attributed_cash_outcomes": 6,
      "attributed_revenue": 9200.0,
      "roas": 2.23,
      "cac": 686.67,
      "attributed_outcomes_total": 18,
      "attributed_pipeline_outcomes": 12,
      "attributed_pipeline_value": 6400.0,
      "meta_reported_conversions": 0,
      "meta_reported_conversion_value": 0.0,
      "cost_per_conversation": 0.33,
      "messaging_conversations_started": 412,
      "first_reply_rate": 41.2,
      "avg_engagement_score": null,
      "reason_codes": [
        { "layer": "attention", "polarity": "strength", "percentile": 88, "sample_confidence": "high" },
        { "layer": "postclick_messaging", "polarity": "strength", "percentile": 91, "sample_confidence": "high" },
        { "layer": "attributed_revenue", "polarity": "strength", "percentile": 74, "sample_confidence": "medium" }
      ]
    }
  ],
  "meta": {
    "profile_id": "uuid"
  }
}

Response fields

FieldTypeDescription
ad_external_idstringPlatform ad id (e.g. Meta ad id).
composite_scorenumber0–100, the cohort-normalized rule blend. null until the ad has been scored. The headline rank.
top_performer_likelihoodnumber0–1 probability — a likelihood, not a guarantee. Not ROAS, not lift — see the note above.
model_versionnumberThe ML ranker version that scored this ad, or null when score_source is rules.
score_sourcestringmodel (the ML ranker produced the likelihood) or rules (it fell back to composite_score).
maturity_stagestringcold · early · mature · calibrated — how settled the score is.
truth_gradestringpredicted (proxy signals only) · attributed (≥1 Atribu-attributed outcome of any kind) · lift (experiment-validated).
primary_outcome_kindstringThe headline outcome to show: cash · pipeline · messaging · meta (Meta's own attribution) · none.
cohort_*stringThe comparison cohort this ad was scored within, plus cohort_n_ads (cohort size).
hook_type / creative_format / cta_type / primary_angle / offersmixedCreative DNA — what to replicate.
attributed_revenue / roas / attributed_cash_outcomes / cacnumberAtribu-attributed cash (null/0 when none).
attributed_outcomes_total / attributed_pipeline_outcomes / attributed_pipeline_valuenumberAll Atribu-attributed conversions (any type); the pipeline subset (leads/appointments/closed-won) + its projected value (not cash).
meta_reported_conversions / meta_reported_conversion_valuenumberMeta's own reported per-ad conversions (last-click — not Atribu's chain; never sets truth_grade).
cost_per_conversation / messaging_conversations_started / first_reply_ratenumberMessaging-objective signals (the "cheap conversations" lens).
reason_codesarray{ layer, polarity: strength|weakness, percentile, sample_confidence: low|medium|high } — why it ranks.

Workspace-wide view

This endpoint is scoped to the API key's profile. The agency-wide cross-profile Top Performers (all clients in one ranked list, plus recurring creative patterns) is available through the Atribu MCP server — top_workspace_performers. See the MCP docs.

Scores build on a daily cadence

Top-performer scores rebuild once a day (independent of the latency-sensitive attribution recompute). A freshly connected Meta account needs one sync cycle before its ads appear here. An empty data array usually means "not scored yet", not "no top performers".

Platform vs Atribu

Endpoint
GET /api/v1/campaigns/platform-comparison

What each ad platform reports it produced, next to what Atribu attributed to the same campaign, ad set or ad under one model. The two are never added together: platforms credit view-through and modeled conversions, use their own windows and date a conversion to the ad interaction; Atribu counts only conversions it can trace to a click, dates them when they happened, and values them by cash collected.

Scope: campaigns:read

Parameters

ParameterTypeRequiredDescription
date_fromstringYesStart date, YYYY-MM-DD. Up to 366 days.
date_tostringYesEnd date, YYYY-MM-DD, inclusive.
modelstringNoAttribution model for the Atribu side. Default last_touch.
levelstringNocampaign, ad_set or ad. Default campaign.

Request

cURL
curl -H "Authorization: Bearer atb_live_YOUR_KEY" \
  "https://api.atribu.app/api/v1/campaigns/platform-comparison?date_from=2026-08-25&date_to=2026-09-23&level=campaign"

Response fields

data.platforms[] holds one total per platform and data.rows[] one row per entity at level. Both carry the same measures:

FieldTypeDescription
platform_conversionsnumber | nullThe platform's own count. null when it reported nothing.
platform_conversion_valuestring | nullThe platform's own value, in the reporting currency.
atribu_conversions / atribu_cash_conversionsintegerConversions Atribu credited here, and the cash subset.
atribu_cash_revenuestringCash Atribu credited here (refunds subtracted).
conversion_gap / conversion_gap_pctnumber | nullAtribu minus platform. Negative: the platform claims more.
value_gapstring | nullAtribu cash minus platform value, exact.
platform_roas / atribu_roasnumber | nullEach side's value over spend.

Each platform total also says what its count means (reported_basis), whether delivery was synced (has_delivery, delivery_through), and how much of Atribu's credit came from paid clicks that named no ad (unassigned_conversions, unassigned_cash_revenue — see GET /api/v1/quality/ad-ids).


On this page