# Ads Attribution API

The Ads Attribution API merges ad-spend data from your connected ad platforms (Meta, Google) with on-site session data and revenue from connected payment providers (Stripe, Foxy) to produce a per-campaign full-funnel report. Use it to answer "which campaigns are paying back?" with revenue-level granularity.

> **Base URL**: `https://app.humblytics.com/api/v1`
>
> Note: this endpoint sits under `/api/v1`, **not** `/api/external/v1` like the [External Analytics API](/external-analytics-api.md). Both bases accept the same property-scoped Bearer API key.

## Authentication

Same property-scoped API key as the External Analytics API. Generate one in the dashboard at **Utilities → API**.

```http
Authorization: Bearer <your_api_key>
```

The `propertyId` in the path must match the property linked to the key.

## Prerequisites

For `revenue`, `revenue_conversions`, and ROAS to populate, the property must have:

1. **At least one ad connector** connected (Meta Ads or Google Ads) via **Connectors** in the dashboard. Without a connector, `spend`, `impressions`, `clicks`, and `roas` come back as `0` / `null`.
2. **A revenue source** connected (Stripe is the most common). Without it, `revenue` and `roas` will be empty even if spend is flowing.
3. **Clean UTM hygiene** on outbound ad creative. Campaigns without `utm_campaign` parameters land in `unmatched_ad_campaigns` (spend visible but no session/revenue join) or `unmatched_utm_campaigns` (sessions visible but no spend join).

***

## Get Ads Attribution

```
GET /properties/{propertyId}/ads-attribution
```

Returns the full per-campaign funnel — impressions → clicks → sessions → revenue — joined across ad platforms and payment providers, plus totals and any unmatched rows.

### Query Parameters

| Name        | Type   | Required | Notes                                     |
| ----------- | ------ | -------- | ----------------------------------------- |
| `startDate` | string | Yes      | ISO date (e.g., `2026-04-01`). Inclusive. |
| `endDate`   | string | Yes      | ISO date (e.g., `2026-04-30`). Inclusive. |

### Sample Request

```bash
curl \
  -H "Authorization: Bearer $HUMBLYTICS_API_KEY" \
  "https://app.humblytics.com/api/v1/properties/PROPERTY_ID/ads-attribution?startDate=2026-04-01&endDate=2026-04-30"
```

### Sample Response

```json
{
  "campaigns": [
    {
      "campaign": "GADS_CORE_PainPoints_2026Q1",
      "utm_campaign": "core_painpoints",
      "platforms": ["google"],
      "target_urls": [
        "https://humblytics.com/solutions/ab-testing?utm_source=google&utm_medium=cpc&utm_campaign=core_painpoints"
      ],
      "top_landing_page": "/solutions/ab-testing",
      "spend": 1240.55,
      "impressions": 84210,
      "clicks": 1832,
      "ad_conversions": 41,
      "sessions": 1654,
      "revenue_conversions": 12,
      "revenue": 4380.00,
      "trial_count": 9,
      "roas": 3.53,
      "true_cpa": 103.38,
      "cost_per_trial": 137.84,
      "click_to_session_rate": 0.903,
      "avg_hours_to_convert": 38.4
    }
  ],
  "totals": {
    "spend": 1240.55,
    "impressions": 84210,
    "clicks": 1832,
    "sessions": 1654,
    "revenue": 4380.00,
    "revenue_conversions": 12,
    "trial_count": 9,
    "roas": 3.53,
    "avg_hours_to_convert": 38.4
  },
  "unmatched_ad_campaigns": [
    {
      "campaign": "META_RETARGETING_Lookalike_v3",
      "platforms": ["meta"],
      "target_urls": ["https://humblytics.com/pricing"],
      "spend": 412.30,
      "impressions": 18204,
      "clicks": 312,
      "note": "Spend visible but no matching utm_campaign found in session data — check UTM hygiene on this campaign."
    }
  ],
  "unmatched_utm_campaigns": [
    {
      "utm_campaign": "newsletter_april",
      "top_landing_page": "/blog/cro-tips",
      "sessions": 84,
      "revenue_conversions": 2,
      "revenue": "180.00",
      "trial_count": 1,
      "note": "Sessions and revenue tracked, but no matching ad spend — likely an organic/email campaign."
    }
  ],
  "breakdowns": {
    "GADS_CORE_PainPoints_2026Q1": {
      "devices": [{ "name": "desktop", "sessions": 1180 }, { "name": "mobile", "sessions": 472 }],
      "countries": [{ "name": "United States", "sessions": 1102 }],
      "browsers": [{ "name": "Chrome", "sessions": 1310 }],
      "os": [{ "name": "macOS", "sessions": 612 }],
      "pages": [{ "name": "/solutions/ab-testing", "sessions": 980 }],
      "contents": [{ "name": "ab-testing", "sessions": 980 }]
    }
  },
  "date_range": { "startDate": "2026-04-01", "endDate": "2026-04-30" },
  "connections": { "google": 1, "meta": 1 }
}
```

### Field Reference

#### `campaigns[]` — fully matched campaigns

These joined successfully across spend, sessions, and revenue data.

| Field                   | Type           | Notes                                                                               |
| ----------------------- | -------------- | ----------------------------------------------------------------------------------- |
| `campaign`              | string         | Platform-side campaign name (e.g., the Google Ads campaign name).                   |
| `utm_campaign`          | string         | The `utm_campaign` value found on session data.                                     |
| `platforms`             | string\[]      | One or more of `"google"`, `"meta"`. Multiple if the same campaign ran across both. |
| `target_urls`           | string\[]      | Distinct landing URLs tagged for this campaign.                                     |
| `top_landing_page`      | string \| null | The single most-visited landing page path.                                          |
| `spend`                 | number         | Total ad spend for the period (in account currency).                                |
| `impressions`           | number         | Total impressions delivered.                                                        |
| `clicks`                | number         | Total clicks reported by the ad platform.                                           |
| `ad_conversions`        | number         | Conversions reported by the ad platform's pixel/tag.                                |
| `sessions`              | number         | Sessions Humblytics attributed to this campaign via UTM match.                      |
| `revenue_conversions`   | number         | Number of revenue events (purchases, paid signups).                                 |
| `revenue`               | number         | Total attributed revenue.                                                           |
| `trial_count`           | number         | Trial starts attributed to this campaign.                                           |
| `roas`                  | number \| null | Revenue ÷ spend. `null` when spend is `0`.                                          |
| `true_cpa`              | number \| null | Spend ÷ revenue\_conversions. The "real" cost per acquired paying customer.         |
| `cost_per_trial`        | number \| null | Spend ÷ trial\_count.                                                               |
| `click_to_session_rate` | number \| null | Sessions ÷ clicks. Useful for spotting tracking gaps (rate ≪ 1 means lost clicks).  |
| `avg_hours_to_convert`  | number \| null | Average time from first session to revenue conversion.                              |

#### `totals`

Roll-up across all matched campaigns. Same fields as `campaigns[]` minus the campaign-specific identifiers.

#### `unmatched_ad_campaigns[]`

Spend was found on the ad platform but no matching `utm_campaign` was seen in session data. This usually means a UTM hygiene issue — the ad creative isn't tagged correctly, so traffic from it can't be attributed to revenue.

#### `unmatched_utm_campaigns[]`

The reverse: sessions and revenue were tagged with a `utm_campaign` value that has no matching ad spend. Often this is organic/email/affiliate traffic that piggybacks on UTM tagging — not a problem.

#### `breakdowns`

Keyed by `campaign`. For each fully matched campaign, returns session counts split by `devices`, `countries`, `browsers`, `os`, `pages`, and `contents` (the `utm_content` value).

#### `connections`

Counts of currently connected ad-platform connections for the property. `{ google: 0, meta: 0 }` is a strong signal the response will be empty — the user needs to connect at least one ad source.

### Notes

* All currency values are in the property's account currency (set when the connector was authorized).
* The endpoint accepts dates only (no time component); timezone is the property's default.
* Empty `campaigns[]` with non-empty `unmatched_*` arrays is the most common signal that UTM hygiene needs work — the data is flowing, it just isn't joining.
* For programmatic access patterns, see [Understanding Attribution](/understanding-your-data/understanding-attribution.md).

## Related Endpoints

* [Ads Connections API](/ads-connections-api.md) — list and inspect Meta and Google Ads connections, pull campaign-level metadata directly from the ad platforms.
* [External Analytics API → Traffic Breakdown](/external-analytics-api.md) — UTM/source breakdown for organic and unattributed traffic.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.humblytics.com/ads-attribution-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
