List metrics

Returns a campaign's results over a window: the analytics funnel (impressions, clicks, conversions, revenue, visitors), the spend each channel's connector reports, and the derived growth KPIs — CTR, CVR, CAC and ROAS.

GET /v1/campaign/{id}/metrics

Addresshttps://api.hanzo.ai/v1/campaign/{id}/metrics
MethodGET
Operationget_campaign_by_id_metrics
AuthAuthorization: Bearer $HANZO_API_KEY

Returns a campaign's results over a window: the analytics funnel (impressions, clicks, conversions, revenue, visitors), the spend each channel's connector reports, and the derived growth KPIs — CTR, CVR, CAC and ROAS.

There is exactly ONE metrics plane and nothing is stored here: the funnel is an analytics query over the campaign's utm_campaign-tagged events, and the spend is each provider's own number read through the org's connector. A warehouse that is not emitting yet degrades to available:false with zeroes — honest-empty, never a 500 and never a fabricated number. When the campaign runs more than one creative and an experiment is wired, abTest carries the A/B analysis.

Request

4 fields.

FieldInTypeRequiredDescription
idpathstringyesID is the campaign to report on, from the path.
rangequerystring—Range is the lookback window: 24h, 7d, 30d or 90d.
startquerystring—Start is an explicit RFC3339 window start.
endquerystring—End is an explicit RFC3339 window end.

Response

StatusBodyMeaning
200campaign.campaignResultsok
defaultproblem-detailsrefused

200 body — 26 fields.

FieldInTypeAlwaysDescription
abTestbodyany—ABTest is the creative A/B analysis from the experiments primitive (experiment.Analyze, pull-model), present only when the campaign runs more than one creative and an experiment is wired.
availablebodyboolean—Available is false when the analytics warehouse is not connected or the query failed: the funnel below is then zero because nothing could be read, not because nothing happened.
cacbodynumber (double)—CAC is customer acquisition cost: spend DOLLARS per conversion, rounded to cents.
campaignIdbodystring—CampaignID is the campaign these results are for, echoed from the request.
channelsbodycampaign.ChannelMetric[]—Channels is the per-channel spend breakdown that SpendCents sums, one row per channel on the campaign including the ones that never launched.
channels[].externalIdbodystring—ExternalID is the provider-side id of the execution the spend belongs to.
channels[].kindbodystring—Kind is which channel this row is: paid, organic or email.
channels[].platformbodystring—Platform is the provider the spend was read from: meta, google, x, instagram, or the email provider.
channels[].spendCentsbodyinteger (int64)—SpendCents is what the provider itself reports this channel spent, in CENTS.
channels[].spendErrorbodystring—SpendError is why this channel's spend could not be read (connector not connected, provider error), as one secret-free line.
channels[].statusbodystring—Status is the channel's launch state on the campaign — pending, live, paused, failed or unavailable.
clicksbodyinteger (int64)—Clicks is the campaign's click events over the window.
conversionsbodyinteger (int64)—Conversions is the terminal funnel events attributed to the campaign — orders completed, signups completed, explicit conversion events.
ctrbodynumber (double)—CTR is clicks per impression, a fraction rounded to 4 places (0.0123 = 1.23%), not a percentage.
cvrbodynumber (double)—CVR is conversions per click, a fraction rounded to 4 places.
endbodystring—End is the window's end, RFC3339 UTC — the read's own clock unless an explicit pair was given.
impressionsbodyinteger (int64)—Impressions is how many times the campaign's creatives were shown, counted from its utm_campaign-tagged impression events.
namebodystring—Name is the campaign's display name at read time, so a result can be labelled without a second fetch.
rangebodystring—Range is the window actually used: 24h, 7d, 30d, 90d, or "custom" when an explicit start/end pair was honored.
revenuebodynumber (double)—Revenue is the summed revenue attribute of the campaign's events, in whole CURRENCY UNITS (dollars) — the one money value here that is not in cents.
roasbodynumber (double)—ROAS is return on ad spend: revenue per spend DOLLAR, rounded to 2 places (2.5 = 2.50backper2.50 back per 1).
sourcebodystring—Source names the analytics table the funnel was read from, so an operator can see exactly what was counted.
spendCentsbodyinteger (int64)—SpendCents is the campaign's total spend in CENTS: the sum of what each live channel's provider reports.
startbodystring—Start is the window's inclusive start, RFC3339 UTC.
statusbodystring—Status is the campaign's lifecycle state at read time — draft, live, paused, completed or failed.
visitorsbodyinteger (int64)—Visitors is how many distinct people the campaign reached, counted by event identity across ALL its events in the window — not a subset of Impressions, so it can exceed them for a campaign whose provider reports clicks but not views.

Failure carries the platform error shape — see Errors.

Examples

hanzo campaign metrics <id>
import { Configuration, CampaignApi } from 'hanzoai';

const api = new CampaignApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.getCampaignByIdMetrics({ id: 'id' });
from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import CampaignApi

client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = CampaignApi(client).get_campaign_by_id_metrics(id='id')
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.CampaignAPI.GetCampaignByIdMetrics(context.Background()).Execute()
if err != nil {
	return err
}
use hanzo_client::apis::{configuration::Configuration, campaign_api};

let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();

let result = campaign_api::get_campaign_by_id_metrics(&cfg, Default::default()).await?;
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.CampaignApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new CampaignApi(client).getCampaignByIdMetrics();
curl https://api.hanzo.ai/v1/campaign/<id>/metrics \
  -H "Authorization: Bearer $HANZO_API_KEY"

MCP reaches campaign through the campaign tool, which names its 9 operations with its own verbs — this one among them, under a name only MCP declares. describe explains any of them:

curl -X POST https://api.hanzo.ai/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "tools/call",
       "params": {
         "name": "describe",
         "arguments": {
           "op": "list_campaigns"
         }
       }
     }'

Campaign API · All Hanzo APIs · Interactive reference

Was this page useful?