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

# Analytics API

> Appeeky API endpoints for Appeeky Analytics, and the ingest endpoint the SDK sends to

There are two APIs:

* The **Appeeky API** (`https://api.appeeky.com/v1/analytics/...`) to turn Analytics on, manage keys, settings and smart links, and read every dashboard view. You call it with your Appeeky API key or a signed-in dashboard session.
* The **ingest endpoint** (`https://ingest.appeeky.com/v1/ingest`) that the SDK sends events to, with the app's publishable key.

***

## Authentication

Appeeky API requests use your normal Appeeky API key (`X-API-Key` or `Authorization: Bearer`), or your dashboard session in the web app. See [Authentication](https://docs.appeeky.com/docs/authentication.md).

> [!NOTE]
>
> Analytics endpoints cost **0 credits**.

`:appId` is the app's id in [My Apps](https://docs.appeeky.com/docs/my-apps.md) (`app_id`). The app must be in your apps, and every endpoint except `enable` needs Analytics to be on for it.

Responses use the standard envelope: `{ "data": … }`.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl "https://api.appeeky.com/v1/analytics/apps/6443843426/dashboard?range=7d" \
  -H "X-API-Key: YOUR_APPEEKY_KEY"
```

***

## Endpoints

### Apps and keys

| Method | Path | Description |
| - | - | - |
| `GET` | `/v1/analytics/apps` | Apps with Analytics on, each with `appId`, `platform`, `publishableKey`, `endpoint` and `enabledAt` |
| `POST` | `/v1/analytics/apps/:appId/enable` | Turn Analytics on and get the publishable key. Returns `201` when created, `200` when it was already on. |
| `POST` | `/v1/analytics/apps/:appId/rotate-key` | Issue a new publishable key. Builds with the old key stop sending. |
| `DELETE` | `/v1/analytics/apps/:appId` | Turn Analytics off and **delete all of the app's analytics data** |
| `GET` | `/v1/analytics/usage` | Events, installs and apps since the start of the month |

### Settings

| Method | Path | Description |
| - | - | - |
| `GET` | `/v1/analytics/apps/:appId/settings` | `{ notifySales, timeZone, funnel }` |
| `PATCH` | `/v1/analytics/apps/:appId/settings` | Change any of the fields below. Returns the new settings. |

| Field | Description |
| - | - |
| `notifySales` | `true` or `false`: Telegram [sale alerts](https://docs.appeeky.com/docs/analytics-alerts.md) for this app |
| `timeZone` | IANA time zone name, for example `Europe/Istanbul`. Sets the day and hour boundaries of every view. |
| `funnel` | Array of 2 to 6 steps (event names or `screen:<name>`), or `null` for the default funnel |

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X PATCH "https://api.appeeky.com/v1/analytics/apps/YOUR_APP_ID/settings" \
  -H "X-API-Key: YOUR_APPEEKY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "timeZone": "Europe/Istanbul", "funnel": ["first_open", "screen:Paywall", "trial_started", "purchase"] }'
```

### Dashboard views

| Method | Path | Description |
| - | - | - |
| `GET` | `/v1/analytics/apps/:appId/dashboard` | KPIs with previous-period values and changes, online users and the chart series |
| `GET` | `/v1/analytics/apps/:appId/breakdown` | Ranked rows for one dimension (`dim` required) |
| `GET` | `/v1/analytics/apps/:appId/funnel` | Ordered funnel for installs first seen in the period |
| `GET` | `/v1/analytics/apps/:appId/retention` | Cohorts: daily for `7d`, weekly for `30d`, none for `today` |
| `GET` | `/v1/analytics/apps/:appId/ltv` | Revenue within 1, 7 and 30 days of install and LTV per install |
| `GET` | `/v1/analytics/apps/:appId/event-names` | Event names and screens seen in the last 30 days, most frequent first |
| `GET` | `/v1/analytics/apps/:appId/links` | Smart links with clicks by platform, installs and revenue |
| `GET` | `/v1/analytics/apps/:appId/skan` | SKAdNetwork / AdAttributionKit postbacks by network and campaign |
| `GET` | `/v1/analytics/apps/:appId/roas` | Apple Search Ads spend next to SDK revenue. See [ROAS](https://docs.appeeky.com/docs/analytics-roas.md). |

Every number is defined in [Metrics](https://docs.appeeky.com/docs/analytics-metrics.md).

### Smart links

| Method | Path | Description |
| - | - | - |
| `POST` | `/v1/analytics/apps/:appId/links` | Create a link: `{ name, campaign, iosUrl?, androidUrl?, deepLink?, webUrl? }`. Returns the link with its `slug` and public `url`. |
| `PATCH` | `/v1/analytics/apps/:appId/links/:linkId` | Update a link. Send only the fields that change. |
| `DELETE` | `/v1/analytics/apps/:appId/links/:linkId` | Delete a link and its click history |

Field rules are on [Smart Links](https://docs.appeeky.com/docs/analytics-smart-links.md#fields).

***

## Query Parameters

| Parameter | Used by | Values |
| - | - | - |
| `range` | dashboard, breakdown, funnel, retention, ltv, links, skan, roas | `today`, `7d` or `30d` (default `30d`). In the app's time zone. |
| `dim` | breakdown | `source`, `campaign`, `keyword`, `country`, `device`, `version`, `screen`, `entry`, `exit` |
| `dim` | ltv | `all` (default), `source`, `campaign`, `keyword`, `country`, `device`, `version` |
| `filter` | dashboard, breakdown, funnel, retention, ltv | `<dimension>:<value>`, repeatable up to 4. Dimensions: `source`, `campaign`, `keyword`, `country`, `device`, `version`. `~none` matches an empty value. |
| `steps` | funnel | Comma-separated steps, for example `first_open,screen:Paywall,trial_started`. Overrides the saved funnel for this request. |
| `level` | roas | `campaign` (default) or `keyword` |

> [!WARNING]
>
> With any `filter`, revenue only counts customers linked to a matching install. Sales without a linked install drop out.

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -G "https://api.appeeky.com/v1/analytics/apps/YOUR_APP_ID/breakdown" \
  -H "X-API-Key: YOUR_APPEEKY_KEY" \
  --data-urlencode "dim=campaign" \
  --data-urlencode "range=30d" \
  --data-urlencode "filter=source:apple_search_ads" \
  --data-urlencode "filter=country:US"
```

***

## Responses

### Dashboard

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": {
    "range": "7d",
    "timeZone": "Europe/Istanbul",
    "since": "2026-10-18T21:00:00.000Z",
    "until": "2026-10-25T11:02:11.000Z",
    "bucket": "day",
    "filters": [],
    "kpis": {
      "installs": { "value": 412, "previous": 377, "change": 0.093 },
      "activeUsers": { "value": 1290, "previous": 1204, "change": 0.071 },
      "revenueUsd": { "value": 734.5, "previous": 690.1, "change": 0.064 },
      "conversion": { "value": 0.041, "previous": 0.037, "change": 0.108 },
      "revenuePerUser": { "value": 0.57, "previous": 0.57, "change": 0 },
      "avgSessionSec": { "value": 184, "previous": 171, "change": 0.076 }
    },
    "onlineUsers": 12,
    "series": [
      { "t": "2026-10-18T21:00:00.000Z", "installs": 61, "activeUsers": 402, "revenueUsd": 98.4 }
    ]
  }
}
```

`conversion` is install → paid as a share (0.041 = 4.1%). `change` is relative (0.093 = +9.3%) and `null` when the previous value is 0.

### Breakdown

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": {
    "dimension": "source",
    "rows": [
      { "key": "organic", "count": 251, "revenueUsd": 310.2 },
      { "key": "apple_search_ads", "count": 120, "revenueUsd": 362.9 },
      { "key": null, "count": 0, "revenueUsd": 61.4 }
    ]
  }
}
```

A `null` key is the empty value: for `source`, sales with no linked install. `revenueUsd` is `null` for `entry` and `exit`.

### Funnel

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": {
    "saved": false,
    "steps": [
      { "step": "first_open", "users": 412, "ofFirst": 1, "ofPrevious": null },
      { "step": "screen:Paywall", "users": 301, "ofFirst": 0.731, "ofPrevious": 0.731 },
      { "step": "trial_started", "users": 38, "ofFirst": 0.092, "ofPrevious": 0.126 },
      { "step": "trial_converted", "users": 11, "ofFirst": 0.027, "ofPrevious": 0.289 }
    ]
  }
}
```

`saved` is `false` when the app uses the default funnel.

### Retention

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": {
    "retention": {
      "unit": "day",
      "lastPeriodPartial": true,
      "cohorts": [
        { "start": "2026-10-18T21:00:00.000Z", "size": 61, "values": [1, 0.34, 0.25, 0.2, 0.18, 0.15, 0.13] }
      ]
    }
  }
}
```

`retention` is `null` for `range=today`. `values[n]` is the share of the cohort active in period `n`, and `null` for periods that have not started.

### LTV

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": {
    "dimension": "source",
    "since": "2026-09-25T21:00:00.000Z",
    "until": "2026-10-25T11:02:11.000Z",
    "rows": [
      {
        "key": "apple_search_ads",
        "installs": 520,
        "payers": 31,
        "revenueUsd": 912.4,
        "windows": [
          { "days": 1, "matureInstalls": 505, "revenueUsd": 401.2, "perInstall": 0.794 },
          { "days": 7, "matureInstalls": 388, "revenueUsd": 602.7, "perInstall": 1.553 },
          { "days": 30, "matureInstalls": 12, "revenueUsd": 30.1, "perInstall": 2.508 }
        ]
      }
    ]
  }
}
```

### Smart links

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": {
    "since": "2026-09-25T21:00:00.000Z",
    "links": [
      {
        "link": {
          "id": "...",
          "slug": "k3x9ab",
          "name": "October newsletter",
          "campaign": "newsletter-oct",
          "iosUrl": "https://apps.apple.com/app/id6443843426",
          "androidUrl": "https://play.google.com/store/apps/details?id=com.example.app",
          "deepLink": "myapp://paywall",
          "webUrl": null,
          "createdAt": "2026-10-01T08:00:00.000Z"
        },
        "clicks": { "total": 248, "ios": 140, "android": 96, "other": 12 },
        "installs": 41,
        "revenueUsd": 88.5
      }
    ]
  }
}
```

`clicks` counts clicks in the period. `installs` counts installs attributed to the link and first seen in the period, and `revenueUsd` is all revenue from those installs so far.

### SKAdNetwork

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "data": {
    "since": "2026-09-25T21:00:00.000Z",
    "until": "2026-10-25T11:02:11.000Z",
    "storeAppId": "6443843426",
    "rows": [
      {
        "kind": "skan",
        "networkId": "v9wttpbfk9.skadnetwork",
        "network": "Meta",
        "sourceIdentifier": "1203",
        "installs": 87,
        "conversions": [
          { "label": "Opened", "count": 52 },
          { "label": "Purchase $28–30", "count": 4 },
          { "label": "Unknown (privacy threshold)", "count": 9 }
        ],
        "estimatedRevenueUsd": 116,
        "laterWindows": [{ "window": 1, "low": 10, "medium": 6, "high": 2, "none": 30 }]
      }
    ]
  }
}
```

See [SKAdNetwork](https://docs.appeeky.com/docs/analytics-skadnetwork.md#reading-the-report) for what each field means.

***

## Errors

| Status | Code | When |
| - | - | - |
| 401 | `AUTH_REQUIRED` | No API key or session |
| 404 | `APP_NOT_FOUND` | `:appId` is not in your apps |
| 404 | `NOT_ENABLED` | Analytics is not on for this app |
| 404 | `NOT_FOUND` | Unknown view, or the link does not exist |
| 400 | `INVALID_DIMENSION` | Unknown `dim` |
| 400 | `INVALID_LINK` | A smart link field is invalid. The message says which. |
| 400 | `INVALID_TIME_ZONE` | `timeZone` is not an IANA name |
| 502 | | The analytics service could not be reached. Retry later. |
| 503 | `NOT_CONFIGURED` | Analytics is not available on this server |

***

## Ingest Endpoint

The SDK sends batches here. You only need it if you write your own client.

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST https://ingest.appeeky.com/v1/ingest
X-Appeeky-Key: apk_pub_...
Content-Type: application/json
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "installId": "6f1c2a9e-1b7d-4b52-9c1e-0d7c0e1f2a3b",
  "sdk": "my-client/1.0.0",
  "context": {
    "platform": "ios",
    "appVersion": "2.4.0",
    "build": "118",
    "osVersion": "18.1",
    "deviceModel": "iPhone16,2",
    "locale": "tr-TR",
    "userId": "$RCAnonymousID:8c1f..."
  },
  "attribution": {
    "adServicesToken": "...",
    "installReferrer": "utm_source=newsletter&utm_campaign=october",
    "deepLinkUrl": "myapp://open?aky_c=spring-launch"
  },
  "events": [
    { "id": "evt_1", "name": "first_open", "ts": 1761390000000, "sessionId": "s_1" },
    { "id": "evt_2", "name": "screen", "screen": "Paywall", "ts": 1761390004000, "sessionId": "s_1" },
    { "id": "evt_3", "name": "export", "props": { "format": "pdf" }, "value": 1, "ts": 1761390010000, "sessionId": "s_1" }
  ]
}
```

| Field | Description |
| - | - |
| `installId` | Random id for the install, up to 64 characters |
| `context` | Optional device context. `userId` is the RevenueCat app user id. |
| `attribution` | Optional. Send once, on the first launch. `adServices` can carry Apple's AdServices answer when the client exchanged the token itself. |
| `events[].id` | Client-generated id, up to 64 characters. Retried events with the same id are not counted twice. |
| `events[].name` | Letters, digits, `_`, `.`, `:` and `-`, up to 64 characters |
| `events[].ts` | Event time in milliseconds since the epoch |
| `events[].props` | Strings (up to 512 characters), numbers, booleans or `null`; up to 4 KB per event |
| `events[].value` | Optional number |

Limits:

* Up to 100 events per batch and 512 KB per request.
* Events older than 30 days, more than 10 minutes in the future, or with properties over 4 KB are dropped and counted in `dropped`; the rest of the batch is kept. A body that does not match the format (for example an invalid event name) is rejected with `400`.
* 600 batches per minute per publishable key.

| Status | Code | When |
| - | - | - |
| 202 | | Accepted: `{ "accepted": 3, "dropped": 0 }` |
| 400 | `INVALID_BATCH` | The body does not match the format |
| 401 | `INVALID_KEY` | Unknown `X-Appeeky-Key` |
| 413 | `TOO_LARGE` | The request is over 512 KB |
| 429 | `RATE_LIMITED` | Too many batches. Keep the batch and retry after the `Retry-After` header. |
| 503 | `INGEST_FAILED` | The batch could not be stored. Retry later. |

***

## Related Docs

* [Metrics](https://docs.appeeky.com/docs/analytics-metrics.md)
* [SDK Reference](https://docs.appeeky.com/docs/analytics-sdk-reference.md)
* [Self-Hosting](https://docs.appeeky.com/docs/analytics-self-hosting.md)


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