AdCrunch Insights API

Aggregated metrics for any level: advertiser, campaign, ad group or ad. The metrics include spend, impressions, clicks, reach and conversions. Group the rows into days, weeks or months, and break them down by provider, by advertiser or by entity type. A date range is required.

Operations 1

GET /observe/insights List insights #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/adcrunch-dev:adcrunch-dev-insights-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

adcrunch-dev-insights-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  contact:
    email: tech@adcrunch.dev
  description: 'Every AdCrunch API, in one document. Each API also publishes its own, at `/openapi/.json`.


    One origin serves the four, and the first segment of a path names the API. `/observe` reads the campaigns, the ads and the Insights of the ad accounts your organization connects. `/mutations` changes what runs on them. `/context` holds the Skills, Brands, Personas, Documents and Campaign Plans an organization writes down for its agents. `/assets` holds your images and videos, and places them in the library of an ad account.


    One credential works on the four — see the security scheme.


    The guide explains what these operations share: authentication, the failure shape, and the conventions for ids, money, time and pagination. It also describes three flows that span several operations: a change, an upload, and an edit that does not overwrite.


    Start at https://docs.adcrunch.dev/api/introduction.'
  license:
    name: Proprietary
    url: https://adcrunch.dev
  title: AdCrunch Insights API
  version: 1.0.0
servers:
- description: production stage
  url: https://api.adcrunch.dev
security:
- bearerAuth: []
tags:
- description: 'Aggregated metrics for any level: advertiser, campaign, ad group or ad. The metrics include spend, impressions, clicks, reach and conversions. Group the rows into days, weeks or months, and break them down by provider, by advertiser or by entity type. A date range is required.'
  name: Insights
paths:
  /observe/insights:
    get:
      security:
      - bearerAuth: []
      description: '**Available on:** ![Meta](https://docs.adcrunch.dev/connect/providers) ![TikTok](https://docs.adcrunch.dev/connect/providers) ![Google Ads](https://docs.adcrunch.dev/connect/providers) ![OpenAI](https://docs.adcrunch.dev/connect/providers)


        Stored read. Gives aggregated metric rows for your organization: what an ad account, a campaign, an ad group or an ad spent over a date range, and what it returned. Each row carries the metrics you name in `select`. The default metrics are `spend` and `impressions`. Each row also carries a `currency`. **A metric a provider does not report reads `0`, and never null.** Google Ads and OpenAI report no reach, so `reach`, `cpp` and `frequency` read `0` on every row of theirs. Compare those three inside one provider only. ## Date range


        **A date range is required.** Send `since`, and optionally `until`, both written `YYYY-MM-DD`. Or send `relative`: `last_7_days`, `last_15_days` or `last_month`. A request with neither is refused with `400 invalid_request`. Set `interval` to `day`, `week` or `month` to get one row for each period, each carrying a `date`. A week is dated by its Monday, a month by its first day. Omit `interval` to get one row for the whole range. ## Filters and groups


        `advertiserId`, `entityId`, `entityType` and `provider` are **filters**: they decide which rows are read. `breakdown` is separate: it decides how the rows are **grouped**, and which columns name the group. | `breakdown` | Rows | Each row also carries |

        | --- | --- | --- |

        | omitted | one, for everything that matched | nothing else |

        | a concept | one for each entity of that level, at every provider | `provider`, `advertiserId`, `entityId`, `type` |

        | `provider` | one for each ad platform | `provider` |

        | `advertiser` | one for each ad account | `provider`, `advertiserId` |

        | a provider entity type | one for each entity of that type | `provider`, `advertiserId`, `entityId`, `type` |


        ### Concepts


        A concept names one level with the same word at every provider. There are five: `campaigns`, `ad-groups`, `ads`, `creatives` and `asset-groups`, the names of the entity resources of this API. | Concept | Meta | TikTok | Google Ads |

        | --- | --- | --- | --- |

        | `campaigns` | `campaign` | `campaign` | `campaign` |

        | `ad-groups` | `adset` | `adgroup` | `ad_group` |

        | `ads` | `ad` | `ad` | `ad_group_ad` |

        | `creatives` | `creative` | — | — |

        | `asset-groups` | — | — | `asset_group` |


        `breakdown=ad-groups` answers one row for each ad group of each provider together. **Each row keeps the word of its provider** in `type`: `adset` on a Meta row, `adgroup` on a TikTok row. A provider that does not have the concept adds no row. A concept is valid with or without `provider`. `entityType` takes a concept too. ### Provider entity types


        A provider entity type is the word of one provider: `campaign`, `adset` at Meta, `adgroup` at TikTok, `ad_group` at Google Ads, `ad`, and so on. It reads only the rows that carry that word, so `breakdown=ad` reads the ads of Meta and TikTok, and not the `ad_group_ad` rows of Google Ads. A provider entity type below `campaign` needs a `provider` or an entity filter. `breakdown=adset` with no `provider` is refused with `400 invalid_request`, and its issue names the breakdowns that are available. Send `breakdown=ad-groups` to read that level at every provider. ## Money


        Money is in **whole units** of the row’s `currency`, with decimals: a `spend` of `1284.57` is 1,284.57. It is the unit a `budget` takes on an entity, so a budget and a spend compare directly. The Mutations API and a Campaign Plan take the same unit. Money comes back in the account currency of the rows it came from, and each row says which in its `currency`. A group that mixes two account currencies answers `currency: null` — the money in it was added across currencies and cannot be compared. Send `currency` — an ISO 4217 code such as `USD` — to make them comparable.'
      x-adcrunch-providers:
      - meta
      - tiktok
      - gads
      - openai
      operationId: listInsights
      parameters:
      - description: Filter rows to a single advertiser. Short-circuits the per-org advertiser fan-out and verifies the advertiser belongs to the caller's organization.
        in: query
        name: advertiserId
        required: false
        schema:
          description: Filter rows to a single advertiser. Short-circuits the per-org advertiser fan-out and verifies the advertiser belongs to the caller's organization.
          type: string
          pattern: ^(acc_)[\s\S]{0,}$
      - description: 'Group results by this level. Send a concept to read one level at every provider: `campaigns`, `ad-groups`, `ads`, `creatives` or `asset-groups`. For example, `ad-groups` reads Meta `adset`, TikTok `adgroup` and Google Ads `ad_group` together. Each row keeps the word of its provider in `type`. A concept is valid with or without `provider`, and a provider that does not have the concept adds no row. A provider-native entity type (`campaign`, `adset`, `adgroup`, `ad_group`, `ad_group_ad`, `ad`, …) reads the word of one provider. Below `campaign`, a native type needs `provider` or an entity filter. `provider` and `advertiser` group by the ad platform and by the ad account. Omit `breakdown` to aggregate every matching row into one result.'
        in: query
        name: breakdown
        required: false
        schema:
          description: 'Group results by this level. Send a concept to read one level at every provider: `campaigns`, `ad-groups`, `ads`, `creatives` or `asset-groups`. For example, `ad-groups` reads Meta `adset`, TikTok `adgroup` and Google Ads `ad_group` together. Each row keeps the word of its provider in `type`. A concept is valid with or without `provider`, and a provider that does not have the concept adds no row. A provider-native entity type (`campaign`, `adset`, `adgroup`, `ad_group`, `ad_group_ad`, `ad`, …) reads the word of one provider. Below `campaign`, a native type needs `provider` or an entity filter. `provider` and `advertiser` group by the ad platform and by the ad account. Omit `breakdown` to aggregate every matching row into one result.'
          type: string
          enum:
          - campaigns
          - ad-groups
          - ads
          - creatives
          - asset-groups
          - provider
          - advertiser
          - campaign
          - adset
          - adgroup
          - ad_group
          - ad_group_ad
          - insertion_order
          - line_item
          - asset_group
          - keyword
          - audience
          - listing_group
          - ad
          - creative
      - description: Display currency (ISO 4217, e.g. `USD`). When provided, monetary metrics are converted from each row’s account currency using the ECB reference rate of the row’s own date, before any aggregation. Omit to get unconverted account-currency values — pass it whenever the organization has advertisers in more than one currency.
        in: query
        name: currency
        required: false
        schema:
          description: Display currency (ISO 4217, e.g. `USD`). When provided, monetary metrics are converted from each row’s account currency using the ECB reference rate of the row’s own date, before any aggregation. Omit to get unconverted account-currency values — pass it whenever the organization has advertisers in more than one currency.
          type: string
          pattern: ^[A-Za-z]{3}$
      - description: 'The `nextCursor` of the previous page. Omit it to get the first page. Send it with no change, and with the same filters as the request that answered it: a cursor from a different query gets a 400 `invalid_cursor`. Do not build or change a cursor.'
        in: query
        name: cursor
        required: false
        schema:
          description: 'The `nextCursor` of the previous page. Omit it to get the first page. Send it with no change, and with the same filters as the request that answered it: a cursor from a different query gets a 400 `invalid_cursor`. Do not build or change a cursor.'
          type: string
          minLength: 1
      - description: Filter to a single entity (any type), or — combined with a concept or an entity-type `breakdown` — scope the breakdown to that entity’s subtree.
        in: query
        name: entityId
        required: false
        schema:
          description: Filter to a single entity (any type), or — combined with a concept or an entity-type `breakdown` — scope the breakdown to that entity’s subtree.
          type: string
      - description: Filter rows to one level. Send a concept (`campaigns`, `ad-groups`, `ads`, `creatives` or `asset-groups`) to read that level at every provider, or a provider-native entity type to read the word of one provider.
        in: query
        name: entityType
        required: false
        schema:
          description: Filter rows to one level. Send a concept (`campaigns`, `ad-groups`, `ads`, `creatives` or `asset-groups`) to read that level at every provider, or a provider-native entity type to read the word of one provider.
          type: string
      - description: Bucket the time series at this granularity. Omit to collapse to a single row per group.
        in: query
        name: interval
        required: false
        schema:
          description: Bucket the time series at this granularity. Omit to collapse to a single row per group.
          type: string
          enum:
          - day
          - week
          - month
      - description: The greatest number of rows on the page, from 1 to 500. The default is 100. A greater value gets a 400, with `error` of `invalid_request`.
        in: query
        name: limit
        required: false
        schema:
          default: 100
          description: The greatest number of rows on the page, from 1 to 500. The default is 100. A greater value gets a 400, with `error` of `invalid_request`.
          type: integer
          minimum: 1
          maximum: 500
      - description: Restrict to a single provider. Ignored when an entity filter (`advertiserId`, etc.) is provided — that filter already pins the provider.
        in: query
        name: provider
        required: false
        schema:
          description: Restrict to a single provider. Ignored when an entity filter (`advertiserId`, etc.) is provided — that filter already pins the provider.
          anyOf:
          - type: string
            enum:
            - meta
          - type: string
            enum:
            - tiktok
          - type: string
            enum:
            - snapchat
          - type: string
            enum:
            - gads
          - type: string
            enum:
            - dv360
          - type: string
            enum:
            - x
          - type: string
            enum:
            - openai
      - in: query
        name: relative
        required: false
        schema:
          anyOf:
          - type: string
            enum:
            - last_15_days
          - type: string
            enum:
            - last_month
          - type: string
            enum:
            - last_7_days
      - description: Metric columns to include on each row, as a comma-separated string (e.g. `spend,clicks,ctr`) or repeated values. Defaults to `spend,impressions`.
        in: query
        name: select
        required: false
        schema:
          description: Metric columns to include on each row, as a comma-separated string (e.g. `spend,clicks,ctr`) or repeated values. Defaults to `spend,impressions`.
          anyOf:
          - type: string
          - type: array
            items:
              type: string
      - in: query
        name: since
        required: false
        schema:
          type: string
      - in: query
        name: until
        required: false
        schema:
          type: string
      responses:
        '200':
          content:
            application/json:
              example:
                data:
                - advertiserId: acc_1203456789012345
                  currency: EUR
                  entityId: '120210000000000'
                  impressions: 184213
                  provider: meta
                  spend: 1284.57
                  type: campaign
                - advertiserId: acc_4829301756
                  currency: EUR
                  entityId: '20481523697'
                  impressions: 46902
                  provider: gads
                  spend: 612.4
                  type: campaign
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        advertiserId:
                          description: The advertiser this row belongs to, prefixed `acc_`. Present when `breakdown` is `advertiser`, a concept or an entity type.
                          type: string
                        currency:
                          description: The ISO 4217 currency the money in this row is expressed in. It is the account currency when every row in the group shares one, the currency you asked for when you sent `currency`, and **null** when the group mixes two or more account currencies. A null here means the money in this row was added up across currencies and cannot be compared — send `currency` to make it comparable.
                          type:
                          - string
                          - 'null'
                        date:
                          description: The first day of the period, `YYYY-MM-DD`. Present only when you send `interval`. A week is dated by its Monday, a month by its first day.
                          type: string
                        entityId:
                          description: The entity this row belongs to, as the bare id its provider gives it. Present when `breakdown` is a concept or an entity type.
                          type: string
                        provider:
                          description: 'The ad platform: `meta`, `tiktok` or `gads`. Present when `breakdown` is set to anything. https://docs.adcrunch.dev/connect/providers lists every provider and what each one reports.'
                          type: string
                        type:
                          description: 'The provider entity type of `entityId`, for example `campaign`, `adset`, `adgroup`, `ad_group` or `ad`. Present when `breakdown` is a concept or an entity type. A concept does not change it: with `breakdown=ad-groups`, a Meta row reads `adset` and a TikTok row reads `adgroup`.'
                          type: string
                        spend:
                          description: Money spent, in the row’s `currency`.
                          type: number
                        clicks:
                          description: Clicks.
                          type: number
                        impressions:
                          description: Impressions.
                          type: number
                        ctr:
                          description: 'Click-through rate, **as a percentage**: clicks ÷ impressions × 100. A `ctr` of 1.5 means 1.5%.'
                          type: number
                        cpc:
                          description: 'Cost per click: spend ÷ clicks.'
                          type: number
                        cpm:
                          description: 'Cost per thousand impressions: spend ÷ impressions × 1000.'
                          type: number
                        cpp:
                          description: 'Cost per thousand people reached: spend ÷ reach × 1000. Google Ads and OpenAI report no reach, so this reads 0 there.'
                          type: number
                        cpa:
                          description: 'Cost per conversion: spend ÷ conversions.'
                          type: number
                        roas:
                          description: 'Return on ad spend: conversion value ÷ spend.'
                          type: number
                        reach:
                          description: People reached. Google Ads and OpenAI do not report it, so it reads 0 there.
                          type: number
                        frequency:
                          description: Impressions ÷ reach. Google Ads and OpenAI report no reach, so this reads 0 there.
                          type: number
                        conversions:
                          description: Conversions, as the provider counts them.
                          type: number
                        conversion_value:
                          description: The value attributed to those conversions, as money.
                          type: number
                        action_add_to_cart:
                          description: Add-to-cart actions. Meta only; other providers read 0.
                          type: number
                        action_add_to_cart_value:
                          description: The value attributed to those add-to-cart actions. Meta only.
                          type: number
                        action_purchase:
                          description: Purchases. Meta only; other providers read 0.
                          type: number
                        action_purchase_value:
                          description: The value attributed to those purchases. Meta only.
                          type: number
                        action_initiate_checkout:
                          description: Checkouts started. Meta only; other providers read 0.
                          type: number
                        action_initiate_checkout_value:
                          description: The value attributed to those checkouts. Meta only.
                          type: number
                      required:
                      - currency
                      additionalProperties: false
                      description: One aggregated row. Which keys it carries is decided by `select`, `breakdown` and `interval` — see each field.
                    description: One row for each group. An empty array means no data matched, which is a normal answer and not a failure.
                  nextCursor:
                    description: Send this value as `cursor` to get the next page. It is absent on the last page.
                    type: string
                required:
                - data
                additionalProperties: false
                example:
                  data:
                  - advertiserId: acc_1203456789012345
                    currency: EUR
                    entityId: '120210000000000'
                    impressions: 184213
                    provider: meta
                    spend: 1284.57
                    type: campaign
                  - advertiserId: acc_4829301756
                    currency: EUR
                    entityId: '20481523697'
                    impressions: 46902
                    provider: gads
                    spend: 612.4
                    type: campaign
          description: One page of the matching rows. This page is the last one, so it carries no `nextCursor`.
        '400':
          content:
            application/json:
              schema:
                anyOf:
                - type: object
                  properties:
                    issues:
                      type: array
                      items:
                        type: object
                        properties:
                          in:
                            type: string
                            enum:
                            - body
                            - cookie
                            - headers
                            - params
                            - query
                            description: The part of the request that holds the field.
                          message:
                            type: string
                            description: A sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
                          path:
                            type: string
                            description: A JSON Pointer into that part of the request, such as `/filename`. An empty string is the whole part.
                        required:
                        - in
                        - message
                        - path
                        additionalProperties: false
                      description: One entry for each field that does not match.
                    error:
                      type: string
                      enum:
                      - invalid_request
                      description: A stable code for the failure. This is the field to branch on. It does not change for a given failure.
                    message:
                      type: string
                      description: A sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
                  required:
                  - issues
                  - error
                  - message
                  additionalProperties: false
                - type: object
                  properties:
                    error:
                      type: string
                      enum:
                      - invalid_cursor
                      description: A stable code for the failure. This is the field to branch on. It does not change for a given failure.
                    message:
                      type: string
                      description: A sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
                  required:
                  - error
                  - message
                  additionalProperties: false
          description: 'The request does not match the schema of this operation: a field is missing or has the wrong type, or the body is not valid JSON. `error` is `invalid_request`, and `issues` names each field. Nothing was changed. Or AdCrunch cannot use the `cursor`: it cannot read it, or the cursor belongs to a different query. Then `error` is `invalid_cursor`. Send the `nextCursor` of the previous page with no change, or omit `cursor` to get the first page.'
        '401':
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    enum:
                    - unauthorized
                    description: A stable code for the failure. This is the field to branch on. It does not change for a given failure.
                  message:
                    type: string
                    description: A sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
                required:
                - error
                - message
                additionalProperties: false
          description: No API key, or one that does not resolve. See the security scheme. `error` is `unauthorized`.
        '402':
          content:
            application/json:
              schema:
                type: object
                properties:
                  paywallUrl:
                    type: string
                    format: uri
                    description: The page where an owner of the organization subscribes. Show it to the person.
                  error:
                    type: string
                    enum:
                    - organization_unentitled
                    description: A stable code for the failure. This is the field to branch on. It does not change for a given failure.
                  message:
                    type: string
                    description: A sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
                required:
                - paywallUrl
                - error
                - message
                additionalProperties: false
          description: The organization has no active subscription. An owner subscribes at `paywallUrl`. `error` is `organization_unentitled`.
        '403':
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    enum:
                    - forbidden
                    description: A stable code for the failure. This is the field to branch on. It does not change for a given failure.
                  message:
                    type: string
                    description: A sentence to show a person. Written to say what to do next. Reworded whenever it can be said better, so never branch on it.
                required:
                - error
                - message
                additionalProperties: false
          description: The caller does not hold `observe:read`. `error` is `forbidden`.
      summary: List insights
      tags:
      - Insights
components:
  securitySchemes:
    bearerAuth:
      description: 'Send `Authorization: Bearer <credential>`.


        Use an **API key** (`acr_…`), from the AdCrunch console under Settings → API keys.


        The credential names the organization, and no operation takes an organization parameter.


        See https://docs.adcrunch.dev/api/authentication.'
      scheme: bearer
      type: http
x-adcrunch-commit: 7a89aff7eb17461cc80089b9374e622947e37b2b
x-tagGroups:
- name: Observe API
  tags:
  - Insights
  - Campaigns
  - Ad groups
  - Ads
  - Creatives
  - Custom audiences
  - Asset groups
  - Pages
  - Pixels
  - Custom conversions
  - Targeting options
  - Stored reads
- name: Mutations API
  tags:
  - Mutations
- name: Context API
  tags:
  - Skills
  - Brands
  - Personas
  - Documents
  - Campaign Plans
  - Line Items
- name: Assets API
  tags:
  - Assets