curl --request GET \
--url https://api.datalyr.com/v1/attribution \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.datalyr.com/v1/attribution"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.datalyr.com/v1/attribution', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.datalyr.com/v1/attribution",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.datalyr.com/v1/attribution"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.datalyr.com/v1/attribution")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.datalyr.com/v1/attribution")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"channels": [
{
"channel": "<string>",
"paid": true,
"spend": 123,
"spend_currency_assumed_rows": 123,
"visitors": 123,
"conversions": 123,
"revenue_usd": 123,
"events": {}
}
],
"unattributed": {
"conversions": 123,
"revenue_usd": 123
},
"totals": {
"conversions": 123,
"revenue_usd": 123,
"spend": 123,
"spend_currency_assumed_rows": 123
},
"meta": {
"grain": "channel",
"model": "last_touch",
"model_source": "request",
"window_days": 123,
"window_days_requested": 123,
"window_days_source": "request",
"conversion_events": [
"<string>"
],
"date_range": {
"start": "<string>",
"end": "<string>"
},
"revenue_floor": "<string>",
"from_clamped": true
},
"complete": true
}{
"error": "<string>"
}{
"error": "<string>"
}Get attribution
Attributed conversions and revenue by channel under the requested attribution model. Returns per-channel visitors, deduped ad spend, conversions and USD revenue, plus an explicit unattributed bucket — conversions with no eligible touch. That bucket is never redistributed across channels.
Weighted models (linear, time_decay) share each conversion across its eligible touches, so per-channel conversions are fractional; they still sum to the total. spend is null on unpaid channels and on paid channels with no spend rows — null means no spend data, not zero spend.
grain picks the row level. channel (the default) returns the response below. source, campaign, adset and ad return the QueryResult of POST /query: one row per value with attributed_conversions, attributed_revenue, attributed_spend and attributed_roas, sorted by revenue, at most 100 rows. The model and window it used are in meta.resolved.attribution.
curl --request GET \
--url https://api.datalyr.com/v1/attribution \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.datalyr.com/v1/attribution"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.datalyr.com/v1/attribution', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.datalyr.com/v1/attribution",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.datalyr.com/v1/attribution"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.datalyr.com/v1/attribution")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.datalyr.com/v1/attribution")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"channels": [
{
"channel": "<string>",
"paid": true,
"spend": 123,
"spend_currency_assumed_rows": 123,
"visitors": 123,
"conversions": 123,
"revenue_usd": 123,
"events": {}
}
],
"unattributed": {
"conversions": 123,
"revenue_usd": 123
},
"totals": {
"conversions": 123,
"revenue_usd": 123,
"spend": 123,
"spend_currency_assumed_rows": 123
},
"meta": {
"grain": "channel",
"model": "last_touch",
"model_source": "request",
"window_days": 123,
"window_days_requested": 123,
"window_days_source": "request",
"conversion_events": [
"<string>"
],
"date_range": {
"start": "<string>",
"end": "<string>"
},
"revenue_floor": "<string>",
"from_clamped": true
},
"complete": true
}{
"error": "<string>"
}{
"error": "<string>"
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Query Parameters
Inclusive ISO 8601 start date.
Inclusive ISO 8601 end date.
Attribution model. time_decay halves a touch's credit every 7 days. Omit to use the workspace's configured default.
last_touch, first_touch, linear, time_decay Attribution lookback in days: a touch earns credit only if it was live inside this window before the conversion. Omit to use the workspace's configured window. The engine's ceiling is 90 — a larger request is answered with 90 and reports both in meta.window_days and meta.window_days_requested.
1 <= x <= 365Optional comma-separated custom event names (max 8) to count per channel alongside revenue. Counts appear as events on each channel row and on unattributed. Revenue attribution itself always covers every money row. At a non-channel grain the first 6 become attributed:<event_name> columns.
Row level. channel is the certified channel summary. source, campaign, adset and ad answer through the query layer and return a QueryResult.
channel, source, campaign, adset, ad Was this page helpful?