> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trygravity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Dashboard API

> Query your dashboard data programmatically using your API key.

Pull the same metrics you see in the dashboard (revenue, impressions, placements, devices, geography) from scripts, cron jobs, or custom integrations. Reporting endpoints are read-only; `POST /publisher-dashboard/placements` lets you create placements programmatically.

## Base URL

```
https://platform.trygravity.ai
```

## Authentication

Every request must include your Gravity API key in the `X-API-Key` header. Grab the key from your [dashboard](https://app.trygravity.com) under **Settings → Platform Settings**.

```bash theme={null}
curl https://platform.trygravity.ai/publisher-dashboard/info \
  -H "X-API-Key: YOUR_API_KEY"
```

<Note>
  This is the same API key used to serve ads. No extra credentials required.
</Note>

***

## Endpoints

### GET `/publisher-dashboard/info`

Publisher profile and lifetime totals.

<ParamField header="X-API-Key" type="string" required>
  Your Gravity API key.
</ParamField>

<RequestExample>
  ```bash theme={null}
  curl https://platform.trygravity.ai/publisher-dashboard/info \
    -H "X-API-Key: YOUR_API_KEY"
  ```
</RequestExample>

**Response**

```json theme={null}
{
  "publisher_id": "abc-123",
  "name": "My Platform",
  "url": "https://myplatform.com",
  "payout_model": "CPM",
  "total_impressions": 7800000,
  "total_clicks": 42000
}
```

***

### GET `/publisher-dashboard/stats`

Daily performance time series — impressions, clicks, revenue, CPM, CPC, CTR.

<ParamField query="days" type="integer" default="30">
  Number of days to look back (1–3650).
</ParamField>

<ParamField query="start_date" type="string">
  Start date (`YYYY-MM-DD`). Overrides `days` when paired with `end_date`.
</ParamField>

<ParamField query="end_date" type="string">
  End date (`YYYY-MM-DD`).
</ParamField>

<ParamField query="tz" type="string" default="UTC">
  IANA timezone for date bucketing (e.g. `America/New_York`).
</ParamField>

<RequestExample>
  ```bash theme={null}
  curl "https://platform.trygravity.ai/publisher-dashboard/stats?days=7&tz=America/New_York" \
    -H "X-API-Key: YOUR_API_KEY"
  ```
</RequestExample>

**Response**

```json theme={null}
{
  "totalImpressions": 250000,
  "totalClicks": 1200,
  "totalRevenue": 1250.50,
  "avgCpm": 5.00,
  "avgCpc": 1.04,
  "avgCtr": 0.48,
  "timeSeries": [
    {
      "date": "2025-05-20",
      "impressions": 35000,
      "clicks": 170,
      "revenue": 178.50,
      "cpm": 5.10,
      "cpc": 1.05,
      "ctr": 0.49
    }
  ]
}
```

***

### GET `/publisher-dashboard/activity`

Ad request funnel — requests, wins, impressions, fill rate, show rate.

<ParamField query="days" type="integer" default="7">
  Number of days (1–30).
</ParamField>

<ParamField query="start_date" type="string">
  Start date (`YYYY-MM-DD`).
</ParamField>

<ParamField query="end_date" type="string">
  End date (`YYYY-MM-DD`).
</ParamField>

<ParamField query="tz" type="string" default="UTC">
  IANA timezone.
</ParamField>

<RequestExample>
  ```bash theme={null}
  curl "https://platform.trygravity.ai/publisher-dashboard/activity?days=7" \
    -H "X-API-Key: YOUR_API_KEY"
  ```
</RequestExample>

**Response**

```json theme={null}
{
  "data": [
    {
      "date": "2025-05-20",
      "requests": 50000,
      "wins": 35000,
      "impressions": 30000
    }
  ],
  "total_requests": 350000,
  "total_wins": 245000,
  "total_impressions": 210000,
  "fill_rate": 0.70,
  "show_rate": 0.8571
}
```

| Field | Description |
| - | - |
| `fill_rate` | `wins / requests` — how often a campaign matched. |
| `show_rate` | `impressions / wins` — how often matched ads were viewed. |

***

### GET `/publisher-dashboard/placements`

Per-placement performance breakdown with daily time series.

<ParamField query="days" type="integer" default="7">
  Number of days (1–365).
</ParamField>

<ParamField query="start_date" type="string">
  Start date (`YYYY-MM-DD`).
</ParamField>

<ParamField query="end_date" type="string">
  End date (`YYYY-MM-DD`).
</ParamField>

<RequestExample>
  ```bash theme={null}
  curl "https://platform.trygravity.ai/publisher-dashboard/placements?days=7" \
    -H "X-API-Key: YOUR_API_KEY"
  ```
</RequestExample>

**Response**

```json theme={null}
{
  "placements": [
    {
      "placement": "below_response",
      "impressions": 120000,
      "clicks": 600,
      "ctr": 0.005,
      "revenue": 600.00,
      "cpm": 5.00,
      "cpc": 1.00,
      "daily": [
        {
          "date": "2025-05-20",
          "impressions": 17000,
          "clicks": 85,
          "ctr": 0.005,
          "revenue": 85.00,
          "cpm": 5.00,
          "cpc": 1.00
        }
      ]
    }
  ],
  "period_days": 7
}
```

***

### POST `/publisher-dashboard/placements`

Create a new placement (ad slot) without using the dashboard. The returned `slug` is the `placement_id` to send on ad requests. The placement is created `active`. A new placement can take up to 15 minutes to become servable while the placement cache refreshes; ad requests sent before then get no ad for that slot.

<ParamField body="name" type="string" required>
  Display name (max 100 characters). The slug is derived from it (`"Sidebar Slot"` → `Sidebar-Slot`) and must be unique per publisher.
</ParamField>

<ParamField body="placement_type" type="string" default="below_response">
  One of `above_response`, `below_response`, `inline_response`, `left_response`, `right_response`, `search_result`, `center_page`, `top_page`, `bottom_page`, `left_page`, `right_page`.
</ParamField>

<ParamField body="device" type="string" default="all">
  One of `all`, `desktop`, `mobile`, `tablet`.
</ParamField>

<ParamField body="framework" type="string" default="any">
  One of `any`, `react`, `nextjs`, `vite`, `react-native`, `swift`, `vanilla`, `other`.
</ParamField>

<ParamField body="page_url" type="string">
  URL of the page or screen where the slot lives.
</ParamField>

<ParamField body="description" type="string">
  Free-form notes.
</ParamField>

<ParamField body="display_config" type="object">
  Optional `{ "max_ad_text_chars": integer }`: caps ad body length for this slot. Minimum 120.
</ParamField>

<RequestExample>
  ```bash theme={null}
  curl -X POST https://platform.trygravity.ai/publisher-dashboard/placements \
    -H "X-API-Key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Sidebar Slot",
      "placement_type": "right_response",
      "device": "desktop",
      "page_url": "https://myplatform.com/chat"
    }'
  ```
</RequestExample>

**Response** (`201 Created`)

```json theme={null}
{
  "id": "6f1c2d3e-...",
  "publisher_id": "abc-123",
  "name": "Sidebar Slot",
  "slug": "Sidebar-Slot",
  "placement_type": "right_response",
  "device": "desktop",
  "framework": "any",
  "page_url": "https://myplatform.com/chat",
  "description": null,
  "screenshot_url": null,
  "screenshot_region": null,
  "status": "active",
  "display_config": null,
  "created_at": "2026-09-10T20:45:00+00:00",
  "updated_at": "2026-09-10T20:45:00+00:00"
}
```

| Status | Reason |
| - | - |
| `409` | A placement with the same slug already exists for your publisher. |
| `422` | `name` is empty, has no alphanumeric characters, or exceeds 100 characters; an enum value is invalid; or `max_ad_text_chars` is below 120. |

***

### GET `/publisher-dashboard/devices`

Performance breakdown by device type (desktop, mobile, tablet).

<ParamField query="days" type="integer" default="30">
  Number of days (1–365).
</ParamField>

<ParamField query="start_date" type="string">
  Start date (`YYYY-MM-DD`).
</ParamField>

<ParamField query="end_date" type="string">
  End date (`YYYY-MM-DD`).
</ParamField>

<RequestExample>
  ```bash theme={null}
  curl "https://platform.trygravity.ai/publisher-dashboard/devices?days=30" \
    -H "X-API-Key: YOUR_API_KEY"
  ```
</RequestExample>

**Response**

```json theme={null}
{
  "devices": [
    {
      "device_type": "desktop",
      "impressions": 150000,
      "clicks": 750,
      "ctr": 0.005,
      "revenue": 750.00,
      "cpm": 5.00,
      "cpc": 1.00,
      "daily": [
        {
          "date": "2025-05-20",
          "device_type": "desktop",
          "impressions": 5000,
          "clicks": 25,
          "ctr": 0.005,
          "revenue": 25.00,
          "cpm": 5.00,
          "cpc": 1.00
        }
      ]
    }
  ],
  "period_days": 30
}
```

***

### GET `/publisher-dashboard/geography`

Per-country performance breakdown.

<ParamField query="days" type="integer" default="30">
  Number of days (1–365).
</ParamField>

<ParamField query="start_date" type="string">
  Start date (`YYYY-MM-DD`).
</ParamField>

<ParamField query="end_date" type="string">
  End date (`YYYY-MM-DD`).
</ParamField>

<RequestExample>
  ```bash theme={null}
  curl "https://platform.trygravity.ai/publisher-dashboard/geography?days=30" \
    -H "X-API-Key: YOUR_API_KEY"
  ```
</RequestExample>

**Response**

```json theme={null}
{
  "countries": [
    {
      "country_code": "US",
      "impressions": 500000,
      "clicks": 2500,
      "ctr": 0.005,
      "revenue": 2500.00,
      "cpm": 5.00,
      "cpc": 1.00
    }
  ],
  "period_days": 30
}
```

***

### GET `/publisher-dashboard/countries`

Top countries by user count.

<ParamField query="limit" type="integer" default="20">
  Number of countries to return (1–100).
</ParamField>

<RequestExample>
  ```bash theme={null}
  curl "https://platform.trygravity.ai/publisher-dashboard/countries?limit=10" \
    -H "X-API-Key: YOUR_API_KEY"
  ```
</RequestExample>

**Response**

```json theme={null}
{
  "countries": [
    {
      "country_code": "US",
      "requests": 200000,
      "ads_served": 140000,
      "unique_users": 8000,
      "pct_requests": 57.1
    }
  ]
}
```

***

## MCP server

The reporting endpoints above are also exposed as an [MCP](https://modelcontextprotocol.io) server, so AI agents and MCP-capable clients can query your account directly.

* **Endpoint:** `POST https://platform.trygravity.ai/mcp` (JSON-RPC 2.0 over HTTP)
* **Auth:** `X-API-Key` header (or `Authorization: Bearer <key>`)

A publisher API key unlocks read-only tools mirroring this API: `publisher_get_info`, `publisher_get_stats`, `publisher_get_activity`, `publisher_get_placements`, `publisher_get_devices`, `publisher_get_geography`, and `publisher_get_countries`.

```bash theme={null}
curl https://platform.trygravity.ai/mcp \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}'
```

***

## Code examples

<CodeGroup>
  ```python Python theme={null}
  import requests

  API_KEY = "your-api-key"
  BASE = "https://platform.trygravity.ai/publisher-dashboard"

  # Get last 30 days of performance stats
  stats = requests.get(
      f"{BASE}/stats",
      headers={"X-API-Key": API_KEY},
      params={"days": 30, "tz": "America/New_York"},
  ).json()

  print(f"Impressions: {stats['totalImpressions']:,}")
  print(f"Revenue: ${stats['totalRevenue']:.2f}")
  print(f"eCPM: ${stats['avgCpm']:.2f}")
  ```

  ```javascript JavaScript theme={null}
  const API_KEY = "your-api-key";
  const BASE = "https://platform.trygravity.ai/publisher-dashboard";

  const res = await fetch(`${BASE}/stats?days=30&tz=America/New_York`, {
    headers: { "X-API-Key": API_KEY },
  });
  const stats = await res.json();

  console.log(`Impressions: ${stats.totalImpressions.toLocaleString()}`);
  console.log(`Revenue: $${stats.totalRevenue.toFixed(2)}`);
  console.log(`eCPM: $${stats.avgCpm.toFixed(2)}`);
  ```

  ```bash curl theme={null}
  # Get publisher info
  curl https://platform.trygravity.ai/publisher-dashboard/info \
    -H "X-API-Key: YOUR_API_KEY"

  # Get stats for a specific date range
  curl "https://platform.trygravity.ai/publisher-dashboard/stats?start_date=2025-05-01&end_date=2025-05-31" \
    -H "X-API-Key: YOUR_API_KEY"

  # Get placement breakdown
  curl "https://platform.trygravity.ai/publisher-dashboard/placements?days=7" \
    -H "X-API-Key: YOUR_API_KEY"
  ```
</CodeGroup>

## Errors

| Status | Description |
| - | - |
| `401` | Invalid or missing `X-API-Key`. |
| `400` | Invalid parameter (e.g. bad timezone, out-of-range `days`). |
| `409` | Duplicate placement slug. |
| `422` | Missing required parameter or invalid body field. |

## Questions

Email [support@trygravity.ai](mailto:support@trygravity.ai) for anything API-related. We read it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.