Publisher performance
curl --request GET \
--url https://api-interface.trygravity.com/index/attributions \
--header 'X-API-Key: <x-api-key>'import requests
url = "https://api-interface.trygravity.com/index/attributions"
headers = {"X-API-Key": "<x-api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<x-api-key>'}};
fetch('https://api-interface.trygravity.com/index/attributions', 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-interface.trygravity.com/index/attributions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <x-api-key>"
],
]);
$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-interface.trygravity.com/index/attributions"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<x-api-key>")
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-interface.trygravity.com/index/attributions")
.header("X-API-Key", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-interface.trygravity.com/index/attributions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"publisher_id": "<string>",
"timezone": "<string>",
"start_date": "<string>",
"end_date": "<string>",
"available_from": "<string>",
"summary": {
"revenue_cents": 123,
"index_calls": 123,
"recommendations": 123,
"clicks": 123,
"click_through_rate": {},
"conversions": 123,
"conversion_rate": 123
},
"daily": [
{
"date": "<string>",
"index_calls": 123,
"recommendations": 123,
"clicks": 123,
"conversions": 123
}
]
}Interfaces
Publisher performance
Read the numbers your Index dashboard shows, with your publisher API key
GET
/
index
/
attributions
Publisher performance
curl --request GET \
--url https://api-interface.trygravity.com/index/attributions \
--header 'X-API-Key: <x-api-key>'import requests
url = "https://api-interface.trygravity.com/index/attributions"
headers = {"X-API-Key": "<x-api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<x-api-key>'}};
fetch('https://api-interface.trygravity.com/index/attributions', 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-interface.trygravity.com/index/attributions",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <x-api-key>"
],
]);
$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-interface.trygravity.com/index/attributions"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<x-api-key>")
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-interface.trygravity.com/index/attributions")
.header("X-API-Key", "<x-api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api-interface.trygravity.com/index/attributions")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<x-api-key>'
response = http.request(request)
puts response.read_body{
"publisher_id": "<string>",
"timezone": "<string>",
"start_date": "<string>",
"end_date": "<string>",
"available_from": "<string>",
"summary": {
"revenue_cents": 123,
"index_calls": 123,
"recommendations": 123,
"clicks": 123,
"click_through_rate": {},
"conversions": 123,
"conversion_rate": 123
},
"daily": [
{
"date": "<string>",
"index_calls": 123,
"recommendations": 123,
"clicks": 123,
"conversions": 123
}
]
}The same figures as the Index page of your Gravity dashboard (revenue, index calls,
recommendations, clicks, click-through rate, conversions, conversion rate, plus the daily series
behind the chart), as JSON, for any window in the last 90 days. Both are computed from one shared
query, so the API and the dashboard always agree for the same UTC date range.
Only
Omit both dates for the last 30 days ending today. Polling once a day is plenty; the limit is 60
requests per minute per publisher.
Days are UTC. The dashboard buckets by UTC day too, so a range that matches the dashboard’s
date picker returns the same totals as its cards.
Authentication
Send your publisher API key (the key you already use forPOST /search)
as the X-API-Key header. X-Platform-Api-Key is accepted as an alias.
string
required
Publisher API key. The publisher is resolved from the key alone; there is no publisher parameter.
| Status | Body | Meaning |
|---|---|---|
401 | Invalid API key | The key does not belong to any publisher |
403 | publisher_not_approved | The publisher account is blocked |
403 | index_not_enabled | The publisher has no active Index profile yet (pending accounts included) |
422 | — | Bad date, out-of-range window, or an unsupported query parameter |
429 | — | More than 60 requests per minute for this publisher; retry after Retry-After seconds |
Request
string
default:"publisher"
Must be
publisher (the default). Any other value is 422.string
First UTC day,
YYYY-MM-DD. Defaults to 29 days before end_date (a 30-day window). Must be
on or after available_from (today minus 90 days).string
Last UTC day,
YYYY-MM-DD, inclusive. Defaults to today (UTC). Cannot be in the future or before
start_date.side, start_date and end_date are accepted with an API key. Anything else (limit,
status, …) is 422; those parameters belong to the dashboard session’s view of this route, which
returns a different payload.
Response
string
Your publisher ID
string
Always
UTCstring
First day in the window (
YYYY-MM-DD)string
Last day in the window (
YYYY-MM-DD)string
Earliest day you can request (today minus 90 days)
object
Totals over the window, the dashboard’s cards.
Show child attributes
Show child attributes
integer
Publisher payout in cents from approved, locked, payable, paid or billed conversions
integer
Index searches your platform made
integer
Searches that returned a recommendation
integer
Searches whose tracked link was clicked (one per search, counted on the day of the click)
number | null
clicks divided by searches that returned a tracked link. null when no search in the window
returned a link.integer
Approved conversions attributed to you
number
conversions divided by recommendations; 0 when there were no recommendationsarray
index_calls is usually higher than recommendations: searches that return no match, and
consumer product searches, still count as calls. For a publisher on CPA-only programs this gap is
expected, not a sign that calls are being lost.Example
curl "https://api-interface.trygravity.com/index/attributions?side=publisher&start_date=2026-10-01&end_date=2026-10-07" \
-H "X-API-Key: $GRAVITY_PUBLISHER_KEY"
{
"publisher_id": "2b1f4d4e-9c8a-4f0e-b1b2-5c1b7a3f9d10",
"timezone": "UTC",
"start_date": "2026-10-01",
"end_date": "2026-10-07",
"available_from": "2026-07-23",
"summary": {
"revenue_cents": 1400,
"index_calls": 812,
"recommendations": 403,
"clicks": 57,
"click_through_rate": 0.1414,
"conversions": 2,
"conversion_rate": 0.00496
},
"daily": [
{"date": "2026-10-01", "index_calls": 120, "recommendations": 61, "clicks": 9, "conversions": 0},
{"date": "2026-10-02", "index_calls": 98, "recommendations": 47, "clicks": 6, "conversions": 1},
{"date": "2026-10-03", "index_calls": 0, "recommendations": 0, "clicks": 0, "conversions": 0},
{"date": "2026-10-04", "index_calls": 141, "recommendations": 70, "clicks": 11, "conversions": 0},
{"date": "2026-10-05", "index_calls": 160, "recommendations": 82, "clicks": 12, "conversions": 1},
{"date": "2026-10-06", "index_calls": 150, "recommendations": 74, "clicks": 10, "conversions": 0},
{"date": "2026-10-07", "index_calls": 143, "recommendations": 69, "clicks": 9, "conversions": 0}
]
}

