Skip to main content
Glama

Get ad performance

well_get_ad_performance
Read-only

Get what the ads cost and what they really brought in over a window of days: ad spend, the conversions and the sales value each ad platform claims, the real sales, and the ratios Well computes from them. Use it for ROAS, cost per order, revenue per visit, conversion rate, or spend against sales; use well_list_daily_metrics for raw daily rows.

window names the days: dates, yesterday, last_days (ending yesterday) or an event (black_friday: Friday through Cyber Monday, year_offset -1 for last year's). The result's window gives the resolved from_date and to_date, the workspace timezone they were resolved in, and the event with its year. window.calendars says which day each side counts: ad and visits figures follow each ad account's or analytics property's own reporting day (source_account_day), and sales follow the UTC day of their issue time (utc_day), so the sides can differ by a few hours at each end of the window. window.has_data false means no source holds a row in those days at the level read, no ad source holds spend at another level, and no readable sale was recorded, for example an event still to come: say so, unless missing names unreadable_sales_rows, which says sales rows exist that Well cannot read, and never move to another window or another year yourself. Repeating the read at a level that other_levels_with_spend names keeps the same window, so do that when it names one.

totals holds the window. real_sales is what the store and the invoices really sold, net of tax, each sale counted once (A paid sales order counts, its unpaid rest is owed.); paid_orders counts those sales: each paid store order, and each issued invoice whether or not it is paid. claimed_conversions and claimed_sales_value are what the platforms claim: never revenue, and they can count one sale twice across platforms. ratios are computed, never stored: blended_roas = real sales / spend, claimed_roas = claimed sales value / spend, cost_per_paid_order = spend / paid orders. State a figure as the tool returns it; never recompute or add it.

visits_by_source lists each analytics source's visits on its own, never added together, each with revenue_per_visit = real sales / that source's visits and conversion_rate = paid orders / that source's visits (a fraction, 0.0159 is 1.59 %). Each carries its definition (what it counts), or unknown: then never guess what the source counts from its name. visits_comparable is true only when two or more sources state the same definition; otherwise their definitions differ or are unknown, so state each source's visits as its own figure and never add them.

Money is per currency and never converted. A null figure or ratio was not measured: it is never zero. missing says why: no_source_rows (no connected source reported it), no_sales_source (no store or invoicing tool connected), not_attributable (orders and visits name no campaign, ad account or channel, so those groups carry spend and claims only), sales_read_truncated, several_currencies (no ratio across currencies), source_stale (a source feeding the figure last synced before the window closed (a window that includes today closes at the start of today for this check), so the ratios built on it are null: never read its figure as complete), unreadable_sales_rows (some sales rows have no net amount or no currency, so real sales leave them out), unreadable_sales_check_failed (that check could not run, so say real sales may leave some rows out), day_in_progress (the window includes today: quote the totals as recorded so far, and state no ROAS, cost per order, revenue per visit, conversion rate or spend share for the totals or today until the day closes; the groups of earlier days in a split by day keep their ratios, and the planned spend is null), window_not_started (the window starts after today: its days have not happened, so never state 0 sales, 0 orders or 0 spend for them). When ad_spend is null and other_levels_with_spend names a level, call again with that level.

Each connected source in ad_sources, sales_sources and visits_sources gives synced_at, fresh_enough and window_rows (none when it wrote nothing for the window, for example a source that stopped syncing): when a source is not fresh enough, or a figure is source_stale, say its figures may be old, and offer well_request_sync with its id. A sync cannot clear day_in_progress or window_not_started, so never offer one for those. window.partial_day true means the window includes today: its totals are what is recorded so far, and the ratios of the totals and of today are null with day_in_progress. The latest days may still change even when the window ended: platforms restate recent days, and a platform's day can follow another timezone than the workspace's. sales_side_unknown true means the workspace's own company is unknown and real sales may include purchases. With group_by, each group carries spend_share: its spend over the window's total spend, per currency (a fraction). With target_orders, plan.planned_spend = the window's spend × target orders / its paid orders, in ratios.currency; null when the window has no cost per paid order. groups_truncated true means more than 200 groups: narrow the range before you rank them.

When the token authorizes one workspace, call this directly — no workspace call is needed first. When it authorizes several, this read will not guess which one you mean: pass workspace_id on the call.

Input Schema

NameRequiredDescriptionDefault
levelNoThe level the ad figures are read at: campaign (default), ad_set or ad. One level per call.
windowYesThe days to read. dates: from_date to to_date. yesterday: the day before today. last_days: the days that end yesterday. event: black_friday, Friday through Cyber Monday. yesterday, last_days and event read the workspace's calendar.
group_byNoSplit the window: source (each ad account), project (each campaign, ad set or ad of the level), traffic_channel, or day (at most 31 days). The totals only when absent.
workspace_idNoTarget workspace. Omit when the token authorizes one workspace. Required when it authorizes several: this read reports one workspace's own figures and will not choose which.
target_ordersNoA number of paid orders to plan for: the read returns the spend it takes at the window's cost per paid order.
conversation_idNoThe conversation id returned by the previous Well result, in its meta under well/conversation_id, in its structuredContent, or in its JSON text block. Pass it back on every call in the same conversation, including a call a card makes, so the chosen workspace and the earlier answers still apply. It decides the conversation on its own: nothing the host states about the session replaces it. Omit it only on the first call of a conversation.
workspace_scopeNoRestrict this call to the family: the token's primary workspace plus the company workspaces under it that you are a member of. Unrelated authorized workspaces drop out of the read; row reads merge across the family, while a per-workspace figure still reports exactly one workspace.

Output Schema

NameRequiredDescriptionDefault
planNo
errorNo
levelNo
groupsNo
totalsNo
windowNo
missingNo
successYes
ad_sourcesNo
sales_sourcesNo
visits_sourcesNo
conversation_idNoThe conversation this result belongs to. Pass it back as the conversation_id argument on every later Well call in the same conversation.
newly_connectedNoTools that connected to this workspace since the last result and that no session was told about yet, oldest first. Present only when at least one tool is new. The connected-line rule says when to tell an entry; when it does, one line per entry, in the person's language: "<name> is connected.". Never fold several entries into one sentence. Each entry comes back once, on one result only: never repeat its line later.
groups_truncatedNo
visits_comparableNo
resolved_workspaceNoThe workspace that answered, when the caller named none and the token authorizes several.
sales_side_unknownNo
conversation_id_noteNoPresent only when the server opened a fresh lane, stating that no choice recorded earlier was read.
conversation_id_sourceNoWhere the conversation id came from: the host's own request meta, the caller's argument, or a fresh lane the server opened.
other_levels_with_spendNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed14 schema fields changed
    • removedInput schema / properties / from_date
      Removed value: -{
      -  "description": "The first day, as YYYY-MM-DD, included.",
      -  "type": "string"
      -}
    • addedInput schema / properties / target_orders
      Added value: +{
      +  "description": "A number of paid orders to plan for: the read returns the spend it takes at the window's cost per paid order.",
      +  "maximum": 1000000,
      +  "minimum": 1,
      +  "type": "integer"
      +}
    • removedInput schema / properties / to_date
      Removed value: -{
      -  "description": "The last day; the window holds at most 400 days, both ends included, as YYYY-MM-DD, included.",
      -  "type": "string"
      -}
    • addedInput schema / properties / window
      Added value: +{
      +  "description": "The days to read. dates: from_date to to_date. yesterday: the day before today. last_days: the days that end yesterday. event: black_friday, Friday through Cyber Monday. yesterday, last_days and event read the workspace's calendar.",
      +  "oneOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "from_date": {
      +          "description": "The first day, as YYYY-MM-DD, included.",
      +          "type": "string"
      +        },
      +        "kind": {
      +          "const": "dates",
      +          "type": "string"
      +        },
      +        "to_date": {
      +          "description": "The last day; the window holds at most 400 days, both ends included, as YYYY-MM-DD, included.",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "kind",
      +        "from_date",
      +        "to_date"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "kind": {
      +          "const": "yesterday",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "kind"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "days": {
      +          "description": "How many days, ending yesterday.",
      +          "maximum": 400,
      +          "minimum": 1,
      +          "type": "integer"
      +        },
      +        "kind": {
      +          "const": "last_days",
      +          "type": "string"
      +        }
      +      },
      +      "required": [
      +        "kind",
      +        "days"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "event": {
      +          "enum": [
      +            "black_friday"
      +          ],
      +          "type": "string"
      +        },
      +        "kind": {
      +          "const": "event",
      +          "type": "string"
      +        },
      +        "year_offset": {
      +          "description": "0 (default) for this year's event, -1 for last year's.",
      +          "maximum": 0,
      +          "minimum": -10,
      +          "type": "integer"
      +        }
      +      },
      +      "required": [
      +        "kind",
      +        "event"
      +      ],
      +      "type": "object"
      +    }
      +  ]
      +}
    • changedInput schema / required
      Previous value: -[
      -  "from_date",
      -  "to_date"
      -]New value: +[
      +  "window"
      +]
    • addedOutput schema / properties / groups / items / properties / spend_share
      Added value: +{
      +  "anyOf": [
      +    {
      +      "items": {
      +        "additionalProperties": false,
      +        "properties": {
      +          "currency": {
      +            "type": "string"
      +          },
      +          "share": {
      +            "type": "number"
      +          }
      +        },
      +        "required": [
      +          "currency",
      +          "share"
      +        ],
      +        "type": "object"
      +      },
      +      "type": "array"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • changedOutput schema / properties / groups / items / required
      Previous value: -[
      -  "key",
      -  "figures"
      -]New value: +[
      +  "key",
      +  "figures",
      +  "spend_share"
      +]
    • changedOutput schema / properties / missing / items / properties / reason / enum
      Previous value: -[
      -  "no_source_rows",
      -  "no_sales_source",
      -  "not_attributable",
      -  "sales_read_truncated",
      -  "several_currencies",
      -  "source_stale",
      -  "unreadable_sales_rows",
      -  "unreadable_sales_check_failed"
      -]New value: +[
      +  "no_source_rows",
      +  "no_sales_source",
      +  "not_attributable",
      +  "sales_read_truncated",
      +  "several_currencies",
      +  "source_stale",
      +  "unreadable_sales_rows",
      +  "unreadable_sales_check_failed",
      +  "day_in_progress",
      +  "window_not_started"
      +]
    • addedOutput schema / properties / plan
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "planned_spend": {
      +          "type": [
      +            "number",
      +            "null"
      +          ]
      +        },
      +        "target_orders": {
      +          "type": "number"
      +        }
      +      },
      +      "required": [
      +        "target_orders",
      +        "planned_spend"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedOutput schema / properties / window / properties / calendars
      Added value: +{
      +  "additionalProperties": false,
      +  "properties": {
      +    "ad_figures": {
      +      "enum": [
      +        "source_account_day",
      +        "utc_day"
      +      ],
      +      "type": "string"
      +    },
      +    "sales": {
      +      "enum": [
      +        "source_account_day",
      +        "utc_day"
      +      ],
      +      "type": "string"
      +    },
      +    "visits": {
      +      "enum": [
      +        "source_account_day",
      +        "utc_day"
      +      ],
      +      "type": "string"
      +    }
      +  },
      +  "required": [
      +    "ad_figures",
      +    "visits",
      +    "sales"
      +  ],
      +  "type": "object"
      +}
    • addedOutput schema / properties / window / properties / event
      Added value: +{
      +  "anyOf": [
      +    {
      +      "additionalProperties": false,
      +      "properties": {
      +        "event": {
      +          "enum": [
      +            "black_friday"
      +          ],
      +          "type": "string"
      +        },
      +        "year": {
      +          "type": "number"
      +        }
      +      },
      +      "required": [
      +        "event",
      +        "year"
      +      ],
      +      "type": "object"
      +    },
      +    {
      +      "type": "null"
      +    }
      +  ]
      +}
    • addedOutput schema / properties / window / properties / has_data
      Added value: +{
      +  "type": "boolean"
      +}
    • addedOutput schema / properties / window / properties / timezone
      Added value: +{
      +  "type": "string"
      +}
    • changedOutput schema / properties / window / required
      Previous value: -[
      -  "from_date",
      -  "to_date",
      -  "partial_day"
      -]New value: +[
      +  "from_date",
      +  "to_date",
      +  "timezone",
      +  "calendars",
      +  "event",
      +  "has_data",
      +  "partial_day"
      +]
  2. Added

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare a safe read-only operation, but the description adds extensive behavioral context beyond them: null figures are never zero, `missing` reasons explain absent data, `day_in_progress` and `window_not_started` constrain what may be stated, and stale sources must be flagged rather than treated as complete. It also warns never to recompute or add figures and never to move to another window or year automatically.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but front-loads purpose and usage before moving into window semantics, totals, missing-data behavior, and source freshness. It is dense and occasionally repetitive around `day_in_progress`, but the structure is logical and most sentences carry operational guidance rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity, seven parameters, and many edge cases around windows, currencies, stale sources, and partial days, the description is exceptionally complete. An output schema exists, yet the description still explains how to interpret key result fields and when not to state ratios, leaving little ambiguity for an agent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although schema coverage is 100%, the description adds substantial meaning beyond the schema: it explains how `window` resolves dates and calendars, what `event` means for Black Friday, how `group_by` produces `spend_share`, how `target_orders` drives `plan.planned_spend`, and when `workspace_id` is required. These are semantic details an agent would not infer from the schema alone.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: it returns ad spend, claimed conversions and sales value, real sales, and computed ratios over a window. It explicitly distinguishes itself from `well_list_daily_metrics`, which is for raw daily rows, so an agent can select it without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states exactly when to use this tool (ROAS, cost per order, revenue per visit, conversion rate, spend against sales) and names the alternative for raw daily rows. It also gives conditional guidance for workspace authorization, retrying at another level when `other_levels_with_spend` names one, and offering `well_request_sync` only for stale sources.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources