> ## Documentation Index
> Fetch the complete documentation index at: https://docs.upstackdata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# List ads with daily spend and performance metrics

> List every ad from your connected Meta, Google, and TikTok accounts as one flat row per ad, with its campaign and ad set, status, and an optional daily spend or performance series.

**Required scope:** `analytics:read`

Use this to pull every ad with its campaign and ad set in one call, export daily
spend per ad, or compare an ad's last week against the week before. Each row is flat,
so it maps straight onto a spreadsheet or a table in your warehouse.

## Listing or metrics

* Leave out `measures` for a listing: each row has the ad's IDs, names, and
  `basicDetails`, and no `data` key.
* Send `measures` and `dateRange` together to add `data.primary`, a daily series
  per ad. `dateRange` is required whenever `measures` has at least one entry.
* Only ad-platform measures work here (`channel.*` and per-platform ids such as
  `meta.spend` or `google.spend`). Any other measure returns `400` with the
  unsupported ids. [List available measures](/api-reference/catalog/list-available-measures)
  has the full catalog.
* Days with no data for an ad are left out, so an ad that didn't run in the range
  has an empty `data.primary` array.

## Comparison periods

* Send `compareDateRange` to add `data.compare`, a daily series for that period.
  It requires `measures`, and is rejected with `400` without them.
* Nothing is compared unless you ask. There is no automatic preceding period.
* A `compareDateRange` that overlaps `dateRange` is dropped without an error, so the
  rows only carry `data.primary`.

## Filtering which ads come back

Every filter field this endpoint accepts narrows the ad list itself, so it also
changes `pagination.total`.

| Field | Matches | Operators |
| - | - | - |
| `channel.resource_source` | Platform: `facebookIntegration`, `googleAdsIntegration`, `tiktokIntegration` | `equals`, `not_equals`, `in`, `not_in` |
| `channel.account_id`, `channel.campaign_id`, `channel.adset_id`, `channel.ad_id` | Platform IDs | `equals`, `in`, `not_in` |
| `channel.resource_name` (the ad's name), `channel.account_name`, `channel.campaign_name`, `channel.adset_name`, `channel.ad_name` | Names | `equals`, `not_equals`, `in`, `not_in`, `contains`, `not_contains`, `starts_with`, `ends_with` |
| `channel.resource_status`, `channel.resource_configured_status`, `channel.resource_effective_status` | Status values such as `ACTIVE` or `PAUSED` | `equals`, `not_equals`, `in`, `not_in` |

`orders.*`, `events.*`, and `attribution.*` fields aren't accepted here and return
`400`. To see which UTM campaign or ad gets credit for orders, use
[Run an attribution query](/api-reference/analytics/run-an-attribution-query).

## Pagination and sorting

* `limit` is 1 to 500 (default 50) and `offset` skips rows. Keep paging while
  `pagination.hasMore` is `true`. `pagination.total` counts every ad that matches
  `filters`.
* Sort with `sortBy` (`sourceUpdatedAt`, `sourceCreatedAt`, or `resourceName`) and
  `sortDirection` (`asc` or `desc`, lowercase).

## Currency

`currency` (default USD) converts both the daily measures and the budget fields in
`basicDetails` (`dailyBudget`, `budgetRemaining`, `amountSpent`). Budget fields use the
latest exchange rate. After conversion, `basicDetails.currency` is the currency you
asked for and `basicDetails.nativeCurrency` is the ad account's own currency.

## Errors and edge cases

* A filter field this endpoint doesn't accept returns `400`, for example
  `Filter field "attribution.utm_campaign" is not valid for context "query_ads"`.
* A measure that fails to compute leaves that measure out of `data`, but the request
  still returns `200` with the other measures.
* A date-only `dateRange.end` covers that whole day. With `timezone` set, days are
  read in that zone, otherwise in UTC.
* `pixelId` in the body must equal the `x-pixel-id` header, or the request returns `403`.

## Related

* [`upstack query-ads`](/cli/query-ads) runs the same query from the CLI.
* [List channel entities](/api-reference/analytics/list-channel-entities-with-optional-metrics) for accounts, campaigns, or ad sets instead of ads.
* [List filter fields](/api-reference/catalog/list-filter-fields) for the fields each endpoint accepts (`query_ads`).
* [List available measures](/api-reference/catalog/list-available-measures) for measure ids.


## OpenAPI

````yaml /api-reference/openapi.yaml post /db-mgmt/api/query-ads
openapi: 3.1.0
info:
  title: Upstack Data API
  version: '1.0'
  description: >
    Programmatic access to your Upstack Data pixel — analytics queries, the

    measures/dimensions catalog, and dashboard view management.


    All requests authenticate with two headers:


    - `x-api-key`: your Upstack API key (mint one at **Settings → API Keys** in
    the dashboard).

    - `x-pixel-id`: the pixel id the request targets. One key is scoped to one
    pixel.
servers:
  - url: https://api.upstackdata.com
    description: Production
security:
  - apiKey: []
    pixelId: []
tags:
  - name: Analytics
    description: >
      Run measure queries, attribution queries, cohort analyses, and ad-platform
      entity

      listings against your pixel's orders, events, and ad spend. Every query
      endpoint

      takes the same `filters` tree. [List filter
      fields](/api-reference/catalog/list-filter-fields)

      tells you which fields each endpoint accepts.
  - name: Catalog
    description: >
      Look up the ids the query and dashboard endpoints accept: the built-in
      measures, and

      the filter fields with the operators and endpoints each one supports.
  - name: Dashboards
    description: >
      Create, read, copy, update, and delete the dashboard views shown in the
      Upstack web app.

      A view belongs to the pixel in the `x-pixel-id` header, and a key can only
      see its own

      pixel's views.
  - name: Account
    description: >
      Read the account that owns the API key, rename it, and read or replace its
      order

      settings: whether pending and voided orders count, how refunds are dated,
      and which

      orders are excluded from reporting.
  - name: Costs
    description: >
      Read and update cost settings: product defaults, the shipping method, and
      cost lines

      for order fees, payment processing fees, shipping profiles, variable
      costs, and

      recurring expenses. Changes to costs that apply per order recalculate the
      past orders

      they affect, the same as an edit in the web app.
  - name: Products
    description: >
      Search the product variants synced from Shopify and manage per-variant
      costs: manual

      COG lines with effective dates, and handling fees.
  - name: Events
    description: >-
      Upstack Conversion API (CAPI) — send server-side tracking events from your
      backend.
paths:
  /db-mgmt/api/query-ads:
    post:
      tags:
        - Analytics
      summary: List ads with optional daily metrics
      description: >-
        List every ad from your connected Meta, Google, and TikTok accounts as
        one flat row per ad, with its campaign and ad set, status, and an
        optional daily spend or performance series.
      operationId: queryAds
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - pixelId
              properties:
                pixelId:
                  type: string
                  description: Must match the `x-pixel-id` header (403 if it doesn't).
                measures:
                  type: array
                  maxItems: 30
                  description: >-
                    Ad-platform measures to add as a daily series per ad, over
                    `dateRange`. Leave out for a listing with no metrics.
                  items:
                    $ref: '#/components/schemas/MeasureConfig'
                dateRange:
                  $ref: '#/components/schemas/DateRange'
                  description: Required when `measures` is set. Ignored for a listing.
                compareDateRange:
                  $ref: '#/components/schemas/DateRange'
                  description: >-
                    Optional comparison period. Requires `measures`. Dropped
                    without an error when it overlaps `dateRange`.
                filters:
                  $ref: '#/components/schemas/Filter'
                  description: >
                    Narrows which ads are listed. Only `channel.*` fields valid
                    for `query_ads`

                    are accepted. An `or` or `not` group can't mix basic-details
                    and metric

                    fields.
                timezone:
                  type: string
                  description: >-
                    IANA timezone used to read `dateRange` and bucket the daily
                    series. Omit for UTC.
                  example: America/New_York
                currency:
                  type: string
                  default: USD
                  description: >
                    ISO 4217 code to convert measures and `basicDetails` budget
                    amounts to

                    (e.g. `EUR`). **Defaults to `USD` when omitted.** Each row
                    reports the ad

                    account's own currency in `basicDetails.nativeCurrency`.
                limit:
                  type: integer
                  minimum: 1
                  maximum: 500
                  default: 50
                  description: Rows per page.
                offset:
                  type: integer
                  minimum: 0
                  default: 0
                  description: Rows to skip.
                sortBy:
                  type: string
                  enum:
                    - sourceUpdatedAt
                    - sourceCreatedAt
                    - resourceName
                  default: sourceUpdatedAt
                  description: Sort key. `resourceName` is the ad's name.
                sortDirection:
                  type: string
                  enum:
                    - asc
                    - desc
                  default: desc
                  description: Sort direction, lowercase.
            examples:
              listingOnly:
                summary: List 50 ads with no metrics
                value:
                  pixelId: 5f1e6a4f-...
                  limit: 50
              dailySpend:
                summary: Daily google.spend per ad for a week
                value:
                  pixelId: 5f1e6a4f-...
                  measures:
                    - measure: google.spend
                  dateRange:
                    start: '2026-09-14'
                    end: '2026-09-20'
              campaignFilterWithCompare:
                summary: One campaign with spend and a compare period
                value:
                  pixelId: 5f1e6a4f-...
                  measures:
                    - measure: google.spend
                  dateRange:
                    start: '2026-09-14'
                    end: '2026-09-20'
                  compareDateRange:
                    start: '2026-09-07'
                    end: '2026-09-13'
                  filters:
                    and:
                      - field: channel.campaign_id
                        op: equals
                        value: '15011273732'
              activeMetaAds:
                summary: Active Meta ads, sorted by name
                value:
                  pixelId: 5f1e6a4f-...
                  sortBy: resourceName
                  sortDirection: asc
                  filters:
                    and:
                      - field: channel.resource_source
                        op: equals
                        value: facebookIntegration
                      - field: channel.resource_effective_status
                        op: equals
                        value: ACTIVE
      responses:
        '200':
          description: Flat ads listing.
          content:
            application/json:
              schema:
                type: object
                required:
                  - rows
                  - pagination
                properties:
                  rows:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                      description: >
                        One flat row per ad. `adId`, `adName`, `accountId`,
                        `accountName`,

                        `campaignId`, `campaignName`, `adsetId`, `adsetName`,
                        and

                        `resourceSource` are always present. `data` is only
                        present when

                        `measures` was sent.
                      properties:
                        basicDetails:
                          type: object
                          additionalProperties: true
                          description: >
                            The ad's snapshot from the platform: `resourceName`,
                            `resourceSource`,

                            `accountName`, `status`, `configuredStatus`,
                            `effectiveStatus`,

                            `objective`, `dailyBudget`, `budgetRemaining`,
                            `amountSpent`,

                            `currency`, `nativeCurrency`, `timezone`,
                            `bidStrategy`,

                            `optimizationGoal`, `sourceCreatedAt`, and
                            `sourceUpdatedAt`.

                            Fields the platform doesn't report are `null`.
                        data:
                          type: object
                          properties:
                            primary:
                              type: array
                              description: >-
                                One entry per day with data, each with `dt` and
                                one value per measure id. Values are numeric
                                strings.
                              items:
                                $ref: '#/components/schemas/MeasureDataRow'
                            compare:
                              type: array
                              description: >-
                                The same for `compareDateRange`. Present only
                                when a non-overlapping compare period was sent.
                              items:
                                $ref: '#/components/schemas/MeasureDataRow'
                  pagination:
                    type: object
                    required:
                      - limit
                      - offset
                      - total
                      - hasMore
                    properties:
                      limit:
                        type: integer
                      offset:
                        type: integer
                      total:
                        type: integer
                        description: Ads matching `filters`, across all pages.
                      hasMore:
                        type: boolean
                        description: More rows exist past `offset + limit`.
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/ServerError'
components:
  schemas:
    MeasureConfig:
      type: object
      required:
        - measure
      description: |
        A measure entry in a query request. Pass the canonical measure id and an
        optional `pacing` flag.
      properties:
        measure:
          type: string
          description: >
            Canonical measure id (e.g. `orders.gross_revenue`) from

            [List available
            measures](/api-reference/catalog/list-available-measures).

            [Run an analytics
            query](/api-reference/analytics/run-an-analytics-query) also

            accepts the id of a [custom measure](/analytics/custom-measures).
          example: orders.gross_revenue
        pacing:
          type: boolean
          default: false
          description: When `true`, include pacing data for this measure.
    DateRange:
      type: object
      required:
        - start
        - end
      description: Inclusive date range. A date-only `end` covers that whole day.
      properties:
        start:
          type: string
          format: date
          description: First day of the range, as an ISO 8601 date.
          example: '2026-04-01'
        end:
          type: string
          format: date
          description: Last day of the range, as an ISO 8601 date. Included in the results.
          example: '2026-04-30'
    Filter:
      $ref: '#/components/schemas/FilterGroup'
      description: |
        Top-level canonical filter. Alias of `FilterGroup` — every request that
        carries a `filters` field at the body level uses this shape. Example:

        ```json
        {
          "and": [
            { "field": "orders.source_name", "op": "in", "value": ["web", "pos"] },
            { "field": "orders.customer_type", "op": "equals", "value": "new_customer" }
          ]
        }
        ```
    MeasureDataRow:
      type: object
      description: >
        One row of query data. Carries the requested dimension values keyed by
        dimension

        id, and one numeric value per measure keyed by measure id. Time-series
        queries

        (`granularity` other than `none`) add a `dt` bucket.
      additionalProperties: true
      properties:
        dt:
          type: string
          description: >-
            Start of the time bucket, e.g. `2026-04-01T00:00:00.000`. Present
            when `granularity` isn't `none`.
        start:
          type: string
        end:
          type: string
    FilterGroup:
      type: object
      description: |
        Group node — exactly one of `and` / `or` / `not` is set. `and` and `or`
        carry an array of child nodes (leaf or nested group); `not` carries a
        single child node. Nesting depth is capped at 3.
      oneOf:
        - title: All of (and)
          type: object
          required:
            - and
          properties:
            and:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/FilterNode'
        - title: Any of (or)
          type: object
          required:
            - or
          properties:
            or:
              type: array
              minItems: 1
              items:
                $ref: '#/components/schemas/FilterNode'
        - title: Not
          type: object
          required:
            - not
          properties:
            not:
              $ref: '#/components/schemas/FilterNode'
    Error:
      type: object
      required:
        - message
      properties:
        message:
          type: string
          description: Human-readable error message.
        errors:
          type: array
          description: Per-field validation errors (present on 400 responses).
          items:
            type: object
            properties:
              message:
                type: string
              key:
                type: string
              path:
                type: array
                items:
                  type: string
    FilterNode:
      description: Either a `FilterCondition` leaf or a nested `FilterGroup`.
      oneOf:
        - title: Condition
          allOf:
            - $ref: '#/components/schemas/FilterCondition'
        - title: Nested group
          allOf:
            - $ref: '#/components/schemas/FilterGroup'
    FilterCondition:
      type: object
      required:
        - field
        - op
        - value
      description: Leaf node of a canonical filter — a single `field op value` predicate.
      properties:
        field:
          $ref: '#/components/schemas/FilterFieldId'
        op:
          $ref: '#/components/schemas/FilterOperator'
        value:
          $ref: '#/components/schemas/FilterValue'
    FilterFieldId:
      type: string
      description: >
        Canonical filter field id (`<scope>.<snake_case_id>`). Each id is only

        valid on certain endpoints. [List filter
        fields](/api-reference/catalog/list-filter-fields)

        returns the full set and where each one applies.
      enum:
        - orders.source_name
        - orders.customer_type
        - orders.order_type
        - orders.value
        - orders.payment_gateway
        - orders.tags
        - channel.resource_name
        - channel.resource_source
        - channel.resource_status
        - channel.resource_configured_status
        - channel.resource_effective_status
        - channel.account_id
        - channel.campaign_id
        - channel.adset_id
        - channel.ad_id
        - channel.account_name
        - channel.campaign_name
        - channel.adset_name
        - channel.ad_name
        - attribution.utm_source
        - attribution.utm_medium
        - attribution.utm_campaign
        - attribution.utm_adset
        - attribution.utm_term
        - attribution.utm_ad
        - attribution.utm_content
        - events.event_name
        - emq.dataset_id
        - emq.event_name
        - emq.diagnostic_name
    FilterOperator:
      type: string
      description: >
        Operator on a filter condition. Each field accepts its own subset,
        listed in

        `supportedOperators` by [List filter
        fields](/api-reference/catalog/list-filter-fields).
      enum:
        - equals
        - not_equals
        - greater_than
        - less_than
        - greater_than_or_equals
        - less_than_or_equals
        - contains
        - not_contains
        - starts_with
        - ends_with
        - in
        - not_in
        - array_includes
        - array_includes_all
        - array_includes_any
    FilterValue:
      description: |
        Scalar (`string` / `number` / `boolean`) for equality / comparison /
        `contains` operators. Array of scalars for `in`, `not_in`, and
        `array_includes_*` operators.
      oneOf:
        - title: String
          type: string
        - title: Number
          type: number
        - title: Boolean
          type: boolean
        - title: List of strings
          type: array
          items:
            type: string
        - title: List of numbers
          type: array
          items:
            type: number
        - title: List of booleans
          type: array
          items:
            type: boolean
  responses:
    BadRequest:
      description: Validation error. Includes an `errors` array with per-field detail.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: >
        The `x-api-key` or `x-pixel-id` header is missing. The request is
        rejected

        before it reaches the API, and the body is `{"message":
        "Unauthorized"}`.

        A key that is present but not accepted returns `403`, not `401`.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: >
        The key was rejected, or it is valid but not allowed to do this. Either:


        - the key is unknown, revoked, or expired, or the pixel is inactive —
        the body is
          `{"Message": "User is not authorized to access this resource with an explicit deny
          in an identity-based policy"}` (note the capital `M`);
        - the key doesn't carry the scope this endpoint needs, or the body
        `pixelId` doesn't
          match the `x-pixel-id` header — the body is `{"message": "…"}` as described below.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ServerError:
      description: |
        The query failed. The body carries the underlying failure message.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-api-key
      description: Your Upstack API key. Starts with `upstack_`.
    pixelId:
      type: apiKey
      in: header
      name: x-pixel-id
      description: The pixel id the request targets.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.