Conversions, revenue and ROAS per Meta campaign, ad set or ad
The Meta rows of an explore attribution query (see POST /client/v1/data/query) for one client on the caller's roster: every conversion in the window is credited to the person's sessions in the 30 days before it, across devices and CRM contact ids, and the credit lands on the Meta campaign, ad set or ad in the session's landing URL. Spend for the same dates is joined in. The body is the same one /data/query returns for that spec, plus the conversion used, and the two share a cache.
conversion=auto (the default) picks the first source with data in the window: won CRM deals, then purchase (valued by value), then GHL order_completed (valued by activity_value), then appointment_booked, form_submitted or contact_created (no value, for cost per conversion). When none has data the answer is conversion: null with no rows. A deal counts only if its latest status is still won, the same rule attribution applies.
curl -X GET "https://mythic-analytics.gulp.workers.dev/client/v1/extension/performance?location_id=example_string&account_id=example_string&from=2024-12-25&to=2024-12-25&level=campaign&model=last&conversion=auto&value_property=example_string&pipeline=example_string&timezone=example_string" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN"
import requests
import json
url = "https://mythic-analytics.gulp.workers.dev/client/v1/extension/performance?location_id=example_string&account_id=example_string&from=2024-12-25&to=2024-12-25&level=campaign&model=last&conversion=auto&value_property=example_string&pipeline=example_string&timezone=example_string"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
response = requests.get(url, headers=headers)
print(response.json())
const response = await fetch("https://mythic-analytics.gulp.workers.dev/client/v1/extension/performance?location_id=example_string&account_id=example_string&from=2024-12-25&to=2024-12-25&level=campaign&model=last&conversion=auto&value_property=example_string&pipeline=example_string&timezone=example_string", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "https://mythic-analytics.gulp.workers.dev/client/v1/extension/performance?location_id=example_string&account_id=example_string&from=2024-12-25&to=2024-12-25&level=campaign&model=last&conversion=auto&value_property=example_string&pipeline=example_string&timezone=example_string", nil)
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}
require 'net/http'
require 'json'
uri = URI('https://mythic-analytics.gulp.workers.dev/client/v1/extension/performance?location_id=example_string&account_id=example_string&from=2024-12-25&to=2024-12-25&level=campaign&model=last&conversion=auto&value_property=example_string&pipeline=example_string&timezone=example_string')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
response = http.request(request)
puts response.body
{
"success": true,
"data": {
"conversion": {
"conversion": "deals"
},
"kind": "attribution",
"totals": {
"conversions": 75,
"revenue": 210258.9,
"spend": 41200,
"roas": 5.1,
"cpa": 549.33,
"ad_conversions": 3,
"ad_revenue": 4494,
"unmatched_ad_conversions": 0,
"no_touchpoint": 54,
"mixed_currency": false
},
"filtered": {
"rows": 2,
"conversions": 3,
"revenue": 4494,
"spend": 41200,
"roas": 0.11,
"cpa": 13733.33
},
"sampled": false,
"rows": [
{
"type": "ad",
"platform": "meta_ads",
"account_id": "1234567890",
"campaign_id": "120247921827310631",
"campaign_name": "HV - FF - Creative Testing",
"currency": "USD",
"spend": 20600,
"impressions": 812000,
"clicks": 9100,
"conversions": 1,
"revenue": 2497,
"persons": 1,
"cpa": 20600,
"roas": 0.12,
"median_days": 3.6
}
]
}
}
{
"error": "Bad Request",
"message": "The request contains invalid parameters or malformed data",
"code": 400,
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}
{
"error": "Unauthorized",
"message": "Authentication required. Please provide a valid API token",
"code": 401
}
{
"error": "Error",
"message": "`feature_not_in_plan` — the client's plan has no Data API.",
"code": 402
}
{
"error": "Forbidden",
"message": "You don't have permission to access this resource",
"code": 403
}
{
"error": "Too Many Requests",
"message": "Rate limit exceeded. Please try again later",
"code": 429,
"retryAfter": 3600
}
{
"error": "Error",
"message": "`upstream_error` — the query engine failed.",
"code": 502
}
{
"error": "Service Unavailable",
"message": "The service is temporarily unavailable. Please try again later",
"code": 503
}
/client/v1/extension/performance
Target server for requests. Edit to use your own host.
Agency-wide mcp_ key holding extension:read, or an agency key (ak_). A location secret key (sk_) or a client-bound mcp_ key gets 403 agency_key_required. See Using an mcp_ key over HTTP.
mcp_ key holding extension:read, or an agency key (ak_). A location secret key (sk_) or a client-bound mcp_ key gets 403 agency_key_required. See Using an mcp_ key over HTTP.A client on the key's roster.
Meta ad account; an act_ prefix is accepted. Omit for every account.
YYYY-MM-DD. Default 30 days before today (UTC).
YYYY-MM-DD inclusive. Default today.
last = last non-Direct touch.
auto, deals, or event:<event name>.
With conversion=event:<name>. The numeric property holding each conversion's value.
With conversion=deals. Exact GHL pipeline name.
IANA zone the dates are read in. Default UTC.
Request Preview
Response
Response will appear here after sending the request
Authentication
Bearer token. Agency-wide mcp_ key holding extension:read, or an agency key (ak_). A location secret key (sk_) or a client-bound mcp_ key gets 403 agency_key_required. See Using an mcp_ key over HTTP.
Query Parameters
A client on the key's roster.
Meta ad account; an act_ prefix is accepted. Omit for every account.
YYYY-MM-DD. Default 30 days before today (UTC).
YYYY-MM-DD inclusive. Default today.
campaignadsetadauto, deals, or event:<event name>.
With conversion=event:<name>. The numeric property holding each conversion's value.
With conversion=deals. Exact GHL pipeline name.
IANA zone the dates are read in. Default UTC.
Responses
conversion (the source used, or null), totals over every conversion of the client, filtered after the Meta and account filter, sampled, rows[] (one per campaign, ad set or ad with spend, impressions, clicks, conversions, revenue, persons, cpa, roas, median_days, names and account_id), and meta.